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

This commit is contained in:
Martin Edenhofer 2016-03-31 22:54:45 +02:00
parent 8195e0f262
commit 79978a823c
4 changed files with 92 additions and 75 deletions

View file

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

View file

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

View file

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

View file

@ -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 if !instance.find_elements(css: 'body')[0] || instance.find_elements(css: 'body')[0].text =~ /unavailable or too busy/i
instance.navigate.refresh instance.navigate.refresh
end end
sleep 2
screenshot(browser: instance, comment: 'reload_after') screenshot(browser: instance, comment: 'reload_after')
end end