Jobs and tasks
This document compares and provides some practical example usage of two features of the framework: Jobs and Tasks.
- 1 Prerequisites
- 2 Comparison
- 3 Examples
- 3.1 Jobs
- 3.1.1 Create a new job
- 3.1.2 View the available jobs
- 3.1.3 Run a job
- 3.1.4 Check job progress
- 3.2 Tasks
- 3.2.1 Create a new task
- 3.2.2 View the available tasks
- 3.2.3 Run a task
- 3.2.4 Run an ephemeral task
- 3.2.5 Check task progress
- 3.2.6 Tasks and observables
- 3.1 Jobs
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.
A user can inspect jobs, see their status, progress and duration, and control them.
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 |
|---|---|---|
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 | | Futures APIs |
Scheduling execution times | ||
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).
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)
endExample 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), wherejobIdis the Ref id of the job record