Running through the Queue and Busy Waiting
General usecase for the UI is to display information from the database and queue request to the database.
The state in the database is maintained by workers in addition to various tasks that are queued are handled by various workers.
The UI calls methods on models or services, those methods queue tasks that are then acted on by the workers. The workers update the database. Later the UI can see the updated state.
Example: If we power off a VM we really don’t do the API call to RHEV or EC2 or VMware straight. Instead we queue such action and display a flash message or notification saying that the task was queued.
Later the UI will see the updated state in the database (the VM will be down).
In some cases however it is necessary to wait for the result of such task. The task still cannot be done directly as the Appliance running the UI might not be even able to reach the API endpoint of the underlying provider.
Examples of this might be:
- verifying credentials when adding a provider,
- opening a remote console to a VM.
In such cases we have the wait\_for\_task
call.
Example in create
we do a call that returns a task\_id
. Then we call initiate\_wait\_for\_task
.
def create
...
task_id = CloudTenant.create_cloud_tenant_queue(session[:userid], ems, options)
add_flash(_("Cloud tenant creation failed: Task start failed: ID [%{id}]") %
{:id => task_id.inspect}, :error) unless task_id.kind_of?(Fixnum)
if @flash_array
javascript_flash(:spinner_off => true)
else
initiate_wait_for_task(:task_id => task_id, :action => "create_finished")
end
end
This results in a transaction that fired busy waiting in the browser and polling ApplicationController::wait\_for\_task
.
When the task is finished, the :action
passed in is called with the original parameters passed to the create
call plus the task_id.
def create_finished
task_id = session[:async][:params][:task_id]
tenant_name = session[:async][:params][:name]
task = MiqTask.find(task_id)
if MiqTask.status_ok?(task.status)
add_flash(_("%{model} \"%{name}\" created") % {
:model => ui_lookup(:table => 'cloud_tenant'),
:name => tenant_name
})
else
add_flash(_("Unable to create %{model} \"%{name}\": %{details}") % {
:model => ui_lookup(:table => 'cloud_tenant'),
:name => tenant_name,
:details => task.message
}, :error)
end
@breadcrumbs.pop if @breadcrumbs
session[:edit] = nil
session[:flash_msgs] = @flash_array.dup if @flash_array
javascript_redirect :action => "show_list"
end