Skip to content

Commit fcb3fa6

Browse files
authored
Document jobConfig.yaml changes from #1927 (SciCatProject#75)
Update documentation to reflect scicat-backend-next#1931 - Use triple-stash consistently in non-HTML contexts - Document template functions - Rename `performJob` to `perform` (scicat-backend-next 7e99132) * Minor fixes to jobconfig.md - Add TOC - reorder the validate sections - formatting fixes
1 parent 61cd8b7 commit fcb3fa6

File tree

1 file changed

+141
-89
lines changed

1 file changed

+141
-89
lines changed

Development/v4.x/backend/configuration/jobconfig.md

Lines changed: 141 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
# Job Configuration
22

3+
- [Overview](#overview)
4+
- [Quick-start](#quick-start)
5+
- [Details](#details)
6+
- [Job lifecycle](#job-lifecycle)
7+
- [Referencing datasets](#referencing-datasets)
8+
- [Status Codes](#status-codes)
9+
- [Actions](#actions)
10+
- [Migration Notes](#migration-notes)
11+
- [Configuration](#configuration)
12+
- [Configuration overview](#configuration-overview)
13+
- [Authorization](#authorization)
14+
- [Templates](#templates)
15+
- [Actions Configuration](#actions-configuration)
16+
- [URLAction](#urlaction)
17+
- [Validate](#validate)
18+
- [Example 1: Require extra template data](#example-1-require-extra-template-data)
19+
- [Example 2: Enforce datasetLifecycle state](#example-2-enforce-datasetlifecycle-state)
20+
- [Example 3: Define statusCodes](#example-3-define-statuscodes)
21+
- [Email](#email)
22+
- [RabbitMQ](#rabbitmq)
23+
- [Switch](#switch)
24+
- [Error](#error)
25+
- [Log](#log)
26+
27+
328
## Overview
429

530
The SciCat job system is used for any interactions between SciCat and external services.
@@ -22,7 +47,7 @@ false`) and retrieval should be disabled.
2247
To start using jobs:
2348

2449
1. Copy
25-
[jobConfig.recommended.yaml](https://github.com/SciCatProject/scicat-backend-next/blob/master/jobConfig.recommended.yaml)
50+
[`jobConfig.recommended.yaml`](https://github.com/SciCatProject/scicat-backend-next/blob/master/jobConfig.recommended.yaml)
2651
to `jobConfig.yaml`
2752
2. Update the configuration. See
2853
[jobConfig.example.yaml](https://github.com/SciCatProject/scicat-backend-next/blob/master/jobConfig.example.yaml)
@@ -220,17 +245,44 @@ Template strings use [Handlebars](https://handlebarsjs.com/) syntax. The followi
220245
top-level variables are availabe in the handlebars context:
221246

222247
{% raw %}
223-
| Top-level variable | Type | Examples | Description |
224-
|---|---|---|---|
225-
| `request` | `CreateJobDto` or<br/>`UpdateJobDto` | `{{request.type}}`<br/>`{{request.jobParams}}` | HTTP Request body |
226-
| `job` | `JobClass` | `{{job.id}}` | The job, as stored in the database. Not available for validate actions. |
227-
| `datasets` | `DatasetClass[]` | `{{#each datasets}}{{pid}}{{/each}}` | All datasets referenced in `job.jobParams.datasetsList`. |
228-
| `env` | `object` | `{{env.SECRET_TOKEN}}` | Access environmental variables |
248+
| Top-level variable | Type | Examples | Description |
249+
| ------------------ | ------------------------------------ | ---------------------------------------------- | ----------------------------------------------------------------------- |
250+
| `request` | `CreateJobDto` or<br/>`UpdateJobDto` | `{{{request.type}}}`<br/>`{{{request.jobParams}}}` | HTTP Request body |
251+
| `job` | `JobClass` | `{{{job.id}}}` | The job. During the validate phase this is the previous job values (if any); during the perform phase it will be the current database value. |
252+
| `datasets` | `DatasetClass[]` | `{{#each datasets}}{{{pid}}}{{/each}}` | Array of all datasets referenced in `job.jobParams.datasetsList`. |
253+
| `env` | `object` | `{{{env.SECRET_TOKEN}}}` | Access environmental variables |
229254
{% endraw %}
230255

231256
Environmental variables are particularly useful for secrets that should not be stored in
232257
the config file.
233258

259+
{% raw %}
260+
Most variables should use handlebars "triple-stash" (`{{{ var }}}`) to disable html
261+
escaping. Use double-brackets (`{{ var }}`) for HTML email bodies where special
262+
characters should be escaped. Templates that expect JSON should use `{{{ jsonify var
263+
}}}` to ensure correct quoting. In addition to the built-in handlebars functions, the
264+
following additional helpers are defined:
265+
{% endraw %}
266+
267+
- `unwrapJSON`: convert a json object to HTML (arrays become `<ul>`, objects are formatted as key:value lines, etc)
268+
- `keyToWord`: convert camelCase to space-separated words
269+
- `eq`: test exact equality (`===`)
270+
- `jsonify`: Convert an object to JSON
271+
- `job_v3`: Convert a JobClass object to the old JobClassV3
272+
- `urlencode`: urlencode input
273+
- `base64enc`: base64enc input
274+
275+
Not all variables may be available at all times. Actions run either before job is saved
276+
to the database (`validate` phase) or after (`perform` phase). The following table
277+
indicates what values can be expected in the context during each phase.
278+
279+
| Operation | Phase | request | job | datasets |
280+
| --------- | -------- | -------------- | ---------------------------- | ---------------- |
281+
| create | validate | `CreateJobDto` | *undefined* | `DatasetClass[]` |
282+
| create | perform | `CreateJobDto` | `JobClass` | `DatasetClass[]` |
283+
| update | validate | `UpdateJobDto` | `JobClass` (previous values) | `DatasetClass[]` |
284+
| update | perform | `UpdateJobDto` | `JobClass` (updated values) | `DatasetClass[]` |
285+
234286
### Actions Configuration
235287

236288
The following actions are built-in to SciCat and can be included in the `actions` array.
@@ -247,11 +299,12 @@ For example:
247299

248300
```yaml
249301
- actionType: url
250-
url: http://localhost:3000/api/v3/health?jobid={{request.id}}
302+
url: http://localhost:3000/api/v3/health?jobid={{{request.id}}}
251303
method: GET
252304
headers:
253305
accept: application/json
254-
Authorization: "Bearer {{env.ARCHIVER_AUTH_TOKEN}}",
306+
Authorization: "Bearer {{{env.ARCHIVER_AUTH_TOKEN}}}",
307+
body: "{{{jsonify job}}}
255308
```
256309

257310
Where:
@@ -275,8 +328,8 @@ ValidateAction is configured with a series of `<path>: <typecheck>` pairs which
275328
a constraint to be validated. These can be applied to different contexts:
276329

277330
- **`request`** - Checks the incoming request body (aka the DTO).
278-
- **`datasets`** - (CREATE only) requires that a list of datasets be included in
279-
`jobParams.datasetList`. Checks are applied to each dataset
331+
- **`datasets`** - requires that a list of datasets be included in
332+
`jobParams.datasetList`. Checks are applied to each dataset.
280333

281334
Validation occurs before the job gets created in the database, while most other actions
282335
are performed after the job is created. This means that correctly configuring validation
@@ -285,6 +338,46 @@ is important to detect user errors early.
285338
Configuration is described in detail below. However, a few illustrative examples are
286339
provided first.
287340

341+
**Configuration**:
342+
The config file for a validate action will look like this:
343+
344+
```yaml
345+
- actionType: validate
346+
request:
347+
<path>: <typecheck>
348+
datasets:
349+
<path>: <typecheck>
350+
```
351+
352+
Usually `<path>` will be a dot-delimited field in the DTO, eg. "jobParams.name".
353+
Technically it is a [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath)
354+
expression, which is applied to the request body or dataset to extract any matching
355+
items. When writing a jobconfig file it may be helpful to test an expected request body
356+
against the [JSONPath demo](https://jsonpath-plus.github.io/JSONPath/demo/).
357+
358+
The `<typecheck>` expression is a JSON Schema. While complicated schemas are possible,
359+
the combination with JSONPath makes common type checks very concise and legible.
360+
Here are some example `<typecheck>` expressions:
361+
362+
```yaml
363+
- actionType: validate
364+
request: # applies to the request body
365+
jobParams.stringVal: # match simple types
366+
type: string
367+
jobParams.enumVal: # literal values
368+
enum: ["yes", "no"]
369+
jobResultObject.mustBeTrue: # enforce a value
370+
const: true
371+
"jobParams": # Apply external JSON Schema to all params
372+
$ref: https://json.schemastore.org/schema-org-thing.json
373+
dataset: # applies to all datasets
374+
datasetLifecycle.archivable:
375+
const: true
376+
```
377+
378+
Validation will result in a `400 Bad Request` response if either the path is not found
379+
or if any values matching the path do not validate against the provided schema.
380+
288381
##### Example 1: Require extra template data
289382

290383
Consider a case where you want to pass a value from the request body through to other
@@ -301,7 +394,7 @@ POST /jobs
301394
}
302395
```
303396

304-
In this case an `email` action would be configured using handlebars to insert the
397+
In this case an [`email` action](#email) would be configured using handlebars to insert the
305398
`jobParams.subject` value. However, a `validate` action should also be configured to
306399
catch errors early where the subject is not specified:
307400

@@ -318,8 +411,8 @@ jobs:
318411
jobParams.subject:
319412
type: string
320413
- actionType: email
321-
to: "{{job.contactEmail}}"
322-
subject: "[SciCat] {{job.jobParams.subject}}"
414+
to: "{{{job.contactEmail}}}"
415+
subject: "[SciCat] {{{job.jobParams.subject}}}"
323416
bodyTemplate: demo_email.html
324417
update:
325418
auth: admin
@@ -415,49 +508,9 @@ jobs:
415508
- finishedUnsuccessful
416509
```
417510
418-
**Configuration**:
419-
The config file for a validate action will look like this:
420-
421-
```yaml
422-
- actionType: validate
423-
request:
424-
<path>: <typecheck>
425-
datasets:
426-
<path>: <typecheck>
427-
```
428-
429-
Usually `<path>` will be a dot-delimited field in the DTO, eg. "jobParams.name".
430-
Technically it is a [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath)
431-
expression, which is applied to the request body or dataset to extract any matching
432-
items. When writing a jobconfig file it may be helpful to test an expected request body
433-
against the [JSONPath demo](https://jsonpath-plus.github.io/JSONPath/demo/).
434-
435-
The `<typecheck>` expression is a JSON Schema. While complicated schemas are possible,
436-
the combination with JSONPath makes common type checks very concise and legible.
437-
Here are some example `<typecheck>` expressions:
438-
439-
```yaml
440-
- actionType: validate
441-
request: # applies to the request body
442-
jobParams.stringVal: # match simple types
443-
type: string
444-
jobParams.enumVal: # literal values
445-
enum: ["yes", "no"]
446-
jobResultObject.mustBeTrue: # enforce a value
447-
const: true
448-
"jobParams": # Apply external JSON Schema to all params
449-
$ref: https://json.schemastore.org/schema-org-thing.json
450-
dataset: # applies to all datasets
451-
datasetLifecycle.archivable:
452-
const: true
453-
```
454-
455-
Validation will result in a `400 Bad Request` response if either the path is not found
456-
or if any values matching the path do not validate against the provided schema.
457-
458511
#### Email
459512
460-
The `Email` action responds to a Job event by sending an email.
513+
The `email` action responds to a Job event by sending an email.
461514
462515
**Configuration**:
463516
The *Mail service* must first be configured through environmental variables, as described in the [configuration](../configuration.md).
@@ -475,9 +528,9 @@ Example:
475528
476529
```yaml
477530
- actionType: email
478-
to: "{{job.contactEmail}}"
531+
to: "{{{job.contactEmail}}}"
479532
480-
subject: "[SciCat] Your {{job.type}} job was submitted successfully."
533+
subject: "[SciCat] Your {{{job.type}}} job was submitted successfully."
481534
bodyTemplateFile: "path/to/job-template-file.html"
482535
```
483536

@@ -499,7 +552,7 @@ You can create your own template for the email's body, which should be a valid h
499552
</head>
500553
<body>
501554
<p>
502-
Your {{job.type}} job with id {{job.id}} has been submitted ...
555+
Your {{{job.type}}} job with id {{{job.id}}} has been submitted ...
503556
</p>
504557
</body>
505558
</html>
@@ -545,7 +598,7 @@ The action is added to the `actions` section of a job in `jobConfig.yaml` as fol
545598
546599
```yaml
547600
- actionType: switch
548-
scope: request | datasets
601+
phase: validate | perform | all
549602
property: some.property
550603
cases:
551604
- match: exact value match
@@ -560,14 +613,18 @@ The action is added to the `actions` section of a job in `jobConfig.yaml` as fol
560613
561614
- `property` (required) Name of a variable to test against. This is specified as a
562615
JSONPath+ spec; the most common case is a simple dot-delimited list of keys.
563-
- `scope` (required) Determines where the property is looked up. The following values
564-
are supported:
565-
- `request`: Read properties from the job request body (validation phase) or the job
566-
as stored in the database (perform phase).
567-
- `datasets`: Valid only for `create` jobs, properties will be read from the dataset
568-
referenced in `jobParams.datasetList`. If multiple datasets are listed, all should
569-
resolve to a single value; otherwise the job will return a 400 error.
570-
- cases: one or more conditions to match the property against. Conditions are tested in
616+
Properties are selected from the same context used for templates; see
617+
[templates](#templates) above for a description of the values available
618+
- `phase` (required) Determines which phases the switch statement runs. Some properties
619+
may be unavailable in some phases (see [templates](#templates)), requiring limiting
620+
when the switch statement is evaluated. Actions listed within the `cases` section will
621+
also be run only in the phase listed here.
622+
- `validate`: Evaluated before the request is accepted and written to the database;
623+
useful for `validate` actions.
624+
- `perform`: Evaluated after the request is written to the database; most actions
625+
run in this phase.
626+
- `all`: Evaluate the switch condition in both phases
627+
- `cases`: one or more conditions to match the property against. Conditions are tested in
571628
order. No "fall through" behavior is implemented; this can be approximated using yaml
572629
anchors and aliases if needed. The following types of conditions are available:
573630
- `match`: match the property against a string or literal value. This use javascript
@@ -579,9 +636,15 @@ The action is added to the `actions` section of a job in `jobConfig.yaml` as fol
579636
- If no condition is included then the case will always match. This is useful for
580637
adding a terminal 'default' condition (eg with an `error` action).
581638
639+
Some JSON paths may return multiple values. For instance, accessing dataset properties
640+
should use array paths such as `datasets[*].storageLocation`. If multiple unique values
641+
are returned then the request will return a 400 error. If the property doesn't match
642+
any values then a value of `undefined` will be used, which can be handled by a default
643+
case.
644+
582645
**Examples**:
583646
584-
Switch can be used as a simple if statement. For instance, it could be used to respond
647+
Switch can be used as a simple 'if' statement. For instance, it could be used to respond
585648
to different statusCodes (this case could also be handled with handlebars templates):
586649
587650
```yaml
@@ -592,33 +655,22 @@ to different statusCodes (this case could also be handled with handlebars templa
592655
auth: archiveManager
593656
actions:
594657
- actionType: switch
595-
scope: request
596-
property: statusCode
658+
phase: perform
659+
property: job.statusCode
597660
cases:
598661
- match: finishedSuccessful
599662
actions:
600663
- actionType: email
601-
to: {{contactEmail}}
602-
subject: "[SciCat] Your {{type}} job was successful!"
664+
to: {{{job.contactEmail}}}
665+
subject: "[SciCat] Your {{{job.type}}} job was successful!"
603666
bodyTemplateFile: retrieve-success.html
604667
- actions:
605668
- actionType: email
606-
to: {{contactEmail}}
607-
subject: "[SciCat] Your {{type}} job has state {{statusCode}}"
669+
to: {{{job.contactEmail}}}
670+
subject: "[SciCat] Your {{{job.type}}} job has state {{{job.statusCode}}}"
608671
bodyTemplateFile: retrieve-failure.html
609672
```
610673
611-
**Valid properties**:
612-
613-
Generally speaking, actions may be applied either to the request body sent by the client
614-
(such as the `validate` action) or to the job after it is successfully created or
615-
updated in the database (most actions). Currently these are implemented independently,
616-
meaning that, in the request scope, `property` will be matched once against the request
617-
body and then a second time on the updated property from the database. For instance, it
618-
is not possible to use a `switch` action with the job `id` property, since this is not
619-
available in the request body (although it may be present in the URL parameters for
620-
update jobs). This limitation may be relaxed in the future.
621-
622674
#### Error
623675
624676
Throw a custom HTTP error. This can be useful for testing or in combination with a
@@ -641,7 +693,7 @@ database changes.
641693
#### Log
642694
643695
This is a dummy action, useful for debugging. It adds a log entry when executed.
644-
Usually the entry is added after the job request has been processed (`performJob`),
696+
Usually the entry is added after the job request has been processed (`perform`),
645697
but it can also be configured to log messages during initialization or when validating
646698
an incoming job.
647699
@@ -651,7 +703,7 @@ an incoming job.
651703
- actionType: log
652704
init: "Job initialized with params {{{ jsonify this }}}"
653705
validate: "Request body received: {{{ jsonify this }}}"
654-
performJob: "Job saved: {{{ jsonify this }}}"
706+
perform: "Job saved: {{{ jsonify this }}}"
655707
```
656708
657709
All arguments are optional.
@@ -661,7 +713,7 @@ All arguments are optional.
661713
section from jobConfig.yaml is available as a Handlebars context. Default: ""
662714
- `validate` (optional): Log message to print when the job request is received. The
663715
request body (aka DTO) is available as a Handlebars context. Default: ""
664-
- `performJob` (optional): Log message to print after the job is saved to the database.
716+
- `perform` (optional): Log message to print after the job is saved to the database.
665717
The updated job object is available as a Handlebars context.
666-
Default: `"Performing job for {{type}}"`
718+
Default: `"Performing job for {{{job.type}}}"`
667719
{% endraw %}

0 commit comments

Comments
 (0)