Operations

Operations are Lato's system for visually managing the execution of background Jobs.
Operations are handled by several components:

  • The Lato::Operation model initializes all operations and tracks their execution state.
  • The Lato::OperationsController controller manages user access to an ongoing operation.
  • The lato_operation component allows displaying the operation status in the front-end.

Converting a Job into an Operation

The easiest way to convert a Job into an operation is to simply make the Job a subclass of Lato::ApplicationJob.
Additionally, the perform() method must accept a single Hash parameter called params.

# Before
def MyJob < ApplicationJob
  def perform(hello)
    puts hello
  end
end

# After
def MyJob < Lato::ApplicationJob
  def perform(params = {})
    puts params['hello']
  end
end

Generating an Operation

Operations can be generated using the generate method of the Lato::Operation model.
Creating an operation requires three parameters: the name of the job to execute, a Hash of parameters to pass, and the ID of the user requesting the operation.

operation = Lato::Operation.generate('ExportProductsJob', { product_ids: [1, 2, 3] }, @session.user_id)

Once generated, the operation must be started using the start method.
Here is an example controller that starts an operation:

class CustomController < ApplicationController
  def create_operation_action
    @operation = Lato::Operation.generate('OperationExampleJob', {}, @session.user_id)

    respond_to do |format|
      if @operation.start
        format.html { redirect_to lato.operation_path(@operation) }
        format.json { render json: @operation }
      else
        format.html { render :index, status: :unprocessable_entity }
        format.json { render json: @operation.errors, status: :unprocessable_entity }
      end
    end
  end
end

Displaying the Outcome of an Operation

Each operation can be viewed at the route lato.operation_path(operation_id).
To ensure data security, an operation is only accessible to the user who initiated it.

Each operation can have four states: created, running, completed, failed.
The operation view, handled via the lato_operation component, shows the real-time status and output of the operation.
Use the link below to try out an operation:

<%= link_to 'Generate Operation',
  main_app.custom_create_operation_action_path,
  data: { turbo_method: :post }
%>
Generate Operation

Notes

To display the result of an operation directly in-page, you can use lato_action_controller features.
Example:

<%= link_to 'Generate Operation',
  main_app.custom_create_operation_action_path,
  data: { lato_action_target: 'trigger', turbo_method: :post, turbo_frame: 'lato_operation' }
%>
Generate Operation with Success

Handling Operation Outputs

An operation's output can be handled directly within the Job using a series of helper methods.
These functions can also be called even if the Job is executed without using the Lato::Operation model.

Set an Output Message

Generate Operation

class MyJob < Lato::ApplicationJob
  def perform(params = {})
    save_operation_output_message("Operation succeeded with this message")
  end
end

Set an Output File

Generate Operation

class MyJob < Lato::ApplicationJob
  def perform(params = {})
    file_path = Rails.root.join('tmp', 'myfile.csv')
    save_operation_output_file(file_path)
  end
end

Set an Error

Generate Operation

class MyJob < Lato::ApplicationJob
  def perform(params = {})
    raise "This is the operation error message"
  end
end

Update Progress Percentage

Generate Operation

class MyJob < Lato::ApplicationJob
  def perform(params = {})
    10.times do |index|
      sleep(1)
      update_operation_percentage((index + 1) * 10)
    end
  end
end

Set an Input File

<%= form_with
  url: create_operation_action_path(type: 'file_input'),
  data: {
    lato_action_target: 'triggerSubmit',
    turbo_frame: 'lato_operation',
    controller: 'lato-form'
  } do |form| %>

...
class CustomController < ApplicationController
  def create_operation_action
    @operation = Lato::Operation.generate('OperationExampleJob', {}, @session.user_id, params[:file])
    # ...
  end
end
class MyJob < Lato::ApplicationJob
  def perform(params = {})
    save_operation_output_message("You uploaded the file #{operation_input_file_attachment.filename}")
  end
end
You are offline You are online