Jobs and tasks

Jobs and tasks

This document compares and provides some practical example usage of two features of the framework: Jobs and Tasks.

Prerequisites

Read the documentation to understand the basic concepts:

This document is not a replacement or a summary of the documentation; its goal is to provide additional information about the differences between the two features, and hopefully give some hint to help choosing one or the other, depending on the use case.

Comparison

Jobs

FIN Framework offers full UI support for jobs, with a dedicated app.

image-20240201-101918.png

A user can inspect jobs, see their status, progress and duration, and control them.

image-20240201-102041.png

A job can concurrently run multiple times: this means you can repeatedly click the “Run” action of the job, or launch a job multiple times, with different parameters, by Axon/Fantom code. Each jobRun call will return a different handle (a job id), that you can use to inspect the individual progress and status of each job, calling jobStatus(jobHandle) (see more in the examples section).

Jobs can be memory intensive: the job extension will keep the logs of the running jobs available in-memory. For jobs that do extensive logging, this can quickly consume heap.

A job cannot return a result through its APIs. It can only update its progressMsg, which is a string tag, so it’s quite limited (if you need to return a Dict or some complex structure, you will need to serialize it). Another option could be adding a different tag or using a separate record.

It is recommended switching to Tasks, as Jobs are being phased out and could be deprecated in future releases.

Tasks

In FIN, the Task extension is not enabled by default. You need to go to Settings > Ext and manually enable it.

FIN currently does not provide a dedicated app by which the user can inspect tasks status and progress. All the operations can be done only using Folio (Axon functions) or by Fantom code.

A task can not concurrently run multiple times: each task is bound to a queue of messages. Multiple messages can be enqueued, but the task will process them sequentially, one after the other. It’s possible to use ephemeral tasks to run the same function concurrently multiple times, but the downside is that you can’t track the progress of ephemeral tasks, and you can’t even see which ephemeral tasks are running by using the tasks() Axon function.

Tasks are based on Fantom Actor pools, and they allow advanced use cases. When a task is created, you get a Future reference, which provides APIs to easily block until the result is received; while jobs require polling to query the status.

Tasks can return a result, which is easily readable using Future APIs.

Tasks can be integrated with the Observables framework.

Summary

Feature

Jobs

Tasks

Feature

Jobs

Tasks

FIN UI/app support

Concurrent runs of the same job/task instance

Only ephemeral tasks

Sequential runs of the same job/task instance (ensure it does not run concurrently multiple times)

Requires writing synchronization code

Built-in as tasks use message queues

Memory usage

For jobs doing extensive logging, can be expensive

Progress tracking

Only for non-ephemeral tasks

Synchronization (wait until the job/task is completed)

Polling

Futures APIs

Returning a value/result

progressMsg can be used as a workaround, but requires serialization for complex structures

Futures APIs

Scheduling execution times

Jobs | Scheduled Jobs

Observables | Schedule

Observables integration

Requires writing observables code to eventually launch a job

By tagging

Active maintenance

Slowly phased out

Examples

The complete code for these examples can be found here: https://bitbucket.org/finproducts/finglueexamples/src/master/extensions/finExampleExt/

Jobs

Create a new job

A job can be created by simply adding a new record with at least 3 tags: job (marker), dis (string) and jobExpr (string, the function to call).

image-20240202-135407.png

 

Example function - Axon version:

(param: "JOB", n: 5) => do n.times(i => do echo(param + " " + i) jobProgress(i*(100 / n), param + " " + i) jobSleep(1sec) end) end

Example function - Fantom version:

using axon using haystack using jobExt using skyarc using skyarcd const class MyExtLib { static const Str className := MyExt#.name private static Context cx() { Context.cur } @Axon   static Void myTestJobFn(Str param := "JOB", Number maxIterations := 5) { try { iterations := maxIterations.toInt Range(0, iterations, true).each |Int i| { Logger.logInfo(className, "$param $i") Number percent := Number(i * (100 / iterations)) JobLib.jobProgress(percent, "$percent%") JobLib.jobSleep(Number(1, Unit.fromStr("second"))) } JobLib.jobProgress(Number(100), "Done!") } catch (Err e) { Logger.logErr(className, "Error in my test job", e) throw e } } }

Note how jobExt is a dependency of this class, thus it needs to be added to the build.fan to compile.

In both cases, jobProgress is the function used to update the progress percentage as the job proceeds with its work. This can then be monitored by the clients interested (see Check job progress).

If jobProgress or jobSleep are called outside the context of a job (for example, if you call myTestJobFn directly from Folio), they will act as a no-op, and they will not throw an error. This is different for tasks.

View the available jobs

You can see the available jobs using the FIN Jobs app - the list will appear on the right side menu - or by querying readAll(job) in Folio.

Run a job

Manually

It can be done using FIN Jobs app, by clicking on the name of the job, then on “Run”.

Axon

It can be done in two ways:

  • “ephemeral” (not bound to a job record): open Folio and run jobRun(myTestJobFn("ephemeral", 5))

  • running a specific job: jobRun(jobId) , where jobId is the Ref id of the job record