Browse Source

Moved to queue processing of new executed tasks and queue processing for re-render of task bar to prevent race conditions.

Martin Edenhofer 9 years ago
parent
commit
79978a823c

+ 0 - 1
app/assets/javascripts/app/controllers/agent_ticket_create.coffee

@@ -185,7 +185,6 @@ class App.TicketCreate extends App.Controller
     )
 
   render: (template = {}) ->
-    App.TaskManager.touch(@task_key)
 
     # get params
     params = {}

+ 49 - 21
app/assets/javascripts/app/controllers/taskbar_widget.coffee

@@ -26,6 +26,10 @@ class App.TaskbarWidget extends App.Controller
 
   constructor: ->
     super
+
+    @queue = []
+    @queueRunning = false
+
     @renderAll()
 
     dndOptions =
@@ -49,30 +53,56 @@ class App.TaskbarWidget extends App.Controller
     # bind to changes
     @bind('taskInit', => @renderAll())
     @bind('taskUpdate', (tasks) =>
-      @checkChanges(tasks)
+      @queue.push ['taskUpdate', tasks]
+      @uIRunner()
     )
     @bind('taskRemove', (task_ids) =>
-      @checkRemoves(task_ids)
+      @queue.push ['checkRemoves', task_ids]
+      @uIRunner()
     )
 
     # render on generic ui call
-    @bind('ui:rerender', => @renderAll())
+    @bind('ui:rerender', =>
+      @queue.push ['renderAll']
+      @uIRunner()
+    )
 
     # render on login
-    @bind('auth:login', => @renderAll())
+    @bind('auth:login', =>
+      @queue.push ['renderAll']
+      @uIRunner()
+    )
 
     # reset current tasks on logout
-    @bind('auth:logout', => @renderAll())
+    @bind('auth:logout', =>
+      @queue.push ['renderAll']
+      @uIRunner()
+    )
 
-  checkRemoves: (task_ids) ->
-    for task_id in task_ids
-      delete @currentItems[task_id]
-      if @renderList[task_id]
-        @renderList[task_id].remove()
-        delete @renderList[task_id]
+  uIRunner: ->
+    return if !@queue[0]
+    return if @queueRunning
+    @queueRunning = true
+    loop
+      param = @queue.shift()
+      if param[0] is 'taskUpdate'
+        @checkChanges(param[1])
+      else if param[0] is 'checkRemoves'
+        @checkRemoves(param[1])
+      else if param[0] is 'renderAll'
+        @renderAll()
+      if !@queue[0]
+        @queueRunning = false
+        break
+
+  checkRemoves: (keys) ->
+    for key in keys
+      delete @currentItems[key]
+      if @renderList[key]
+        @renderList[key].remove()
+        delete @renderList[key]
 
   checkChanges: (items) ->
-    #console.log('checkChanges', items, @currentItems)
     changedItems = []
     for item in items
       attributes = {}
@@ -81,20 +111,19 @@ class App.TaskbarWidget extends App.Controller
       #console.log('item', item)
       #attributes = item.attributes()
       #console.log('item', @fields.observe, item, attributes)
-      if !@currentItems[item.id]
+      if !@currentItems[item.key]
         changedItems.push item
-        @currentItems[item.id] = attributes
+        @currentItems[item.key] = attributes
       else
-        currentItem = @currentItems[item.id]
+        currentItem = @currentItems[item.key]
         hit = false
         for field of @fields.observe
           diff = _.isEqual(currentItem[field], attributes[field])
           #console.log('diff', field, diff, currentItem[field], attributes[field])
           if !hit && diff
             changedItems.push item
-            @currentItems[item.id] = attributes
+            @currentItems[item.key] = attributes
             hit = true
-    console.log('checkChanges, changedItems', changedItems)
     return if _.isEmpty(changedItems)
     @renderParts(changedItems)
 
@@ -108,17 +137,16 @@ class App.TaskbarWidget extends App.Controller
 
   renderParts: (items) ->
     for item in items
-      if !@renderList[item.id]
+      if !@renderList[item.key]
         @renderItem(item)
       else
-        @renderItem(item, @renderList[item.id])
+        @renderItem(item, @renderList[item.key])
 
   renderItem: (item, el) ->
     html =  $(App.view(@template)(
       item: item
     ))
-    console.log('renderItem', item)
-    @renderList[item.id] = html
+    @renderList[item.key] = html
     if el is false
       return html
     else if !el

+ 43 - 52
app/assets/javascripts/app/lib/app_post/task_manager.coffee

@@ -75,19 +75,21 @@ class _taskManagerSingleton extends App.Controller
 
   init: ->
     @workers           = {}
-    @workersStarted    = {}
-    @tasksStarted      = {}
-    @allTasks          = []
+    @allTasksByKey     = {}
     @tasksToUpdate     = {}
     @activeTaskHistory = []
+    @queue             = []
+    @queueRunning      = false
 
   all: ->
 
     # sort by prio
-    @allTasks = _(@allTasks).sortBy( (task) ->
+    byPrios = []
+    for key, task of @allTasksByKey
+      byPrios.push task
+    _.sortBy(byPrios, (task) ->
       return task.prio
     )
-    return @allTasks
 
   allWithMeta: ->
     all = @all()
@@ -118,7 +120,7 @@ class _taskManagerSingleton extends App.Controller
 
   newPrio: ->
     prio = 1
-    for task in @allTasks
+    for task in @all()
       if task.prio && task.prio > prio
         prio = task.prio
     prio++
@@ -133,21 +135,30 @@ class _taskManagerSingleton extends App.Controller
     return
 
   execute: (params) ->
+    @queue.push params
+    @run()
+
+  run: ->
+    return if !@queue[0]
+    return if @queueRunning
+    @queueRunning = true
+    loop
+      param = @queue.shift()
+      @executeSingel(param)
+      if !@queue[0]
+        @queueRunning = false
+        break
+
+  executeSingel: (params) ->
 
     # input validation
     params.key = App.Utils.htmlAttributeCleanup(params.key)
 
     # in case an init execute arrives later but is aleady executed, ignore it
-    if params.init && @tasksStarted[params.key]
+    if params.init && @workers[params.key]
       #console.log('IGNORE LATER INIT', params)
       return
 
-    # remember started task / prevent to open task twice
-    createNewTask = true
-    if @tasksStarted[params.key]
-      createNewTask = false
-    @tasksStarted[params.key] = true
-
     # if we have init task startups, let the controller know this
     if params.init
       params.params.init = true
@@ -166,10 +177,8 @@ class _taskManagerSingleton extends App.Controller
     # check if task already exists in storage / e. g. from last session
     task = @get(params.key)
 
-    #console.log 'debug', 'execute', params, 'task', task
-
     # create new online task if not exists and if not persistent
-    if !task && createNewTask && !params.persistent
+    if !task && !@workers[params.key] && !params.persistent
       #console.log 'debug', 'add, create new taskbar in backend'
       task = new App.Taskbar
       task.load(
@@ -181,12 +190,13 @@ class _taskManagerSingleton extends App.Controller
         notify:   false
         active:   params.show
       )
-      @allTasks.push task.attributes()
+      @allTasksByKey[params.key] = task.attributes()
 
       # save new task and update task collection
       ui = @
       task.save(
         done: ->
+          ui.allTasksByKey[params.key] = @attributes()
           for taskPosition of ui.allTasks
             if ui.allTasks[taskPosition] && ui.allTasks[taskPosition]['key'] is @key
               task = @attributes()
@@ -206,8 +216,8 @@ class _taskManagerSingleton extends App.Controller
 
     # set all tasks to active false, only new/selected one to active
     if params.show
-      for task in @allTasks
-        if task.key isnt params.key
+      for key, task of @allTasksByKey
+        if key isnt params.key
           if task.active
             task.active = false
             @taskUpdate(task)
@@ -237,10 +247,7 @@ class _taskManagerSingleton extends App.Controller
       params_app['doNotLog'] = 1
 
     # start controller if not already started
-    if !@workersStarted[params.key]
-      @workersStarted[params.key] = true
-
-      # create new controller instanz
+    if !@workers[params.key]
       @workers[params.key] = new App[params.controller](params_app)
 
     # if controller is started hidden, call hide of controller
@@ -252,7 +259,7 @@ class _taskManagerSingleton extends App.Controller
       @showControllerHideOthers(params.key, params_app)
 
   showControllerHideOthers: (thisKey, params_app) =>
-    for key of @workersStarted
+    for key of @workers
       if key is thisKey
         @show(key, params_app)
       else
@@ -294,9 +301,7 @@ class _taskManagerSingleton extends App.Controller
 
   # get task
   get: (key) =>
-    for task in @allTasks
-      if task.key is key
-        return task
+    @allTasksByKey[key]
 
   # get task
   getWithMeta: (key) =>
@@ -321,30 +326,18 @@ class _taskManagerSingleton extends App.Controller
   # remove task certain task from tasks
   remove: (key) =>
 
-    # remember started task
-    delete @tasksStarted[key]
-
-    task = @get(key)
-    return if !task
-
-    # update @allTasks
-    allTasks = _.filter(
-      @allTasks
-      (taskLocal) ->
-        return task if task.key isnt taskLocal.key
-        return
-    )
-    @allTasks = allTasks || []
-
-    # release task from dom and destroy controller
-    @release(key)
+    task = @allTasksByKey[key]
+    delete @allTasksByKey[key]
 
     # rerender taskbar
-    App.Event.trigger('taskRemove', [task.id])
+    App.Event.trigger('taskRemove', [task.key])
 
     # destroy in backend storage
     @taskDestroy(task)
 
+    # release task from dom and destroy controller
+    @release(key)
+
   # set notify of task
   notify: (key) =>
     task = @get(key)
@@ -383,15 +376,13 @@ class _taskManagerSingleton extends App.Controller
     catch
       @log 'notice', "invalid key '#{key}'"
 
-    delete @workersStarted[ key ]
     delete @workers[ key ]
-    delete @tasksStarted[ key ]
 
   # reset while tasks
   reset: =>
 
     # release touch tasks
-    for task in @allTasks
+    for key, task of @allTasksByKey
       @release(key)
 
     # release persistent tasks
@@ -500,7 +491,7 @@ class _taskManagerSingleton extends App.Controller
     tasks = App.Taskbar.all()
     for task in tasks
       task.active = false
-      @allTasks.push task.attributes()
+      @allTasksByKey[task.key] = task.attributes()
 
     # reopen tasks
     App.Event.trigger 'taskbar:init'
@@ -524,13 +515,13 @@ class _taskManagerSingleton extends App.Controller
                   persistent: true
                   init:       true
                 )
-              task_count * 450
+              task_count * 350
               undefined
               'task'
             )
 
     # initial load of taskbar collection
-    for task in @allTasks
+    for key, task of @allTasksByKey
       task_count += 1
       do (task, task_count) =>
         App.Delay.set(
@@ -543,7 +534,7 @@ class _taskManagerSingleton extends App.Controller
               persistent: false
               init:       true
             )
-          task_count * 650
+          task_count * 350
           undefined
           'task'
         )

+ 0 - 1
test/browser_test_helper.rb

@@ -333,7 +333,6 @@ class TestCase < Test::Unit::TestCase
     if !instance.find_elements(css: 'body')[0] || instance.find_elements(css: 'body')[0].text =~ /unavailable or too busy/i
       instance.navigate.refresh
     end
-    sleep 2
     screenshot(browser: instance, comment: 'reload_after')
   end