1
1
# Job Configuration
2
2
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
+
3
28
## Overview
4
29
5
30
The SciCat job system is used for any interactions between SciCat and external services.
@@ -22,7 +47,7 @@ false`) and retrieval should be disabled.
22
47
To start using jobs:
23
48
24
49
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 )
26
51
to ` jobConfig.yaml `
27
52
2 . Update the configuration. See
28
53
[ 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
220
245
top-level variables are availabe in the handlebars context :
221
246
222
247
{% 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 |
229
254
{% endraw %}
230
255
231
256
Environmental variables are particularly useful for secrets that should not be stored in
232
257
the config file.
233
258
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
+
234
286
# ## Actions Configuration
235
287
236
288
The following actions are built-in to SciCat and can be included in the `actions` array.
@@ -247,11 +299,12 @@ For example:
247
299
248
300
` ` ` yaml
249
301
- actionType: url
250
- url: http://localhost:3000/api/v3/health?jobid={{request.id}}
302
+ url: http://localhost:3000/api/v3/health?jobid={{{ request.id} }}
251
303
method: GET
252
304
headers:
253
305
accept: application/json
254
- Authorization: "Bearer {{env.ARCHIVER_AUTH_TOKEN}}",
306
+ Authorization: "Bearer {{{env.ARCHIVER_AUTH_TOKEN}}}",
307
+ body: "{{{jsonify job}}}
255
308
` ` `
256
309
257
310
Where :
@@ -275,8 +328,8 @@ ValidateAction is configured with a series of `<path>: <typecheck>` pairs which
275
328
a constraint to be validated. These can be applied to different contexts :
276
329
277
330
- **`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.
280
333
281
334
Validation occurs before the job gets created in the database, while most other actions
282
335
are performed after the job is created. This means that correctly configuring validation
@@ -285,6 +338,46 @@ is important to detect user errors early.
285
338
Configuration is described in detail below. However, a few illustrative examples are
286
339
provided first.
287
340
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
+
288
381
# #### Example 1: Require extra template data
289
382
290
383
Consider a case where you want to pass a value from the request body through to other
@@ -301,7 +394,7 @@ POST /jobs
301
394
}
302
395
` ` `
303
396
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
305
398
` jobParams.subject` value. However, a `validate` action should also be configured to
306
399
catch errors early where the subject is not specified :
307
400
@@ -318,8 +411,8 @@ jobs:
318
411
jobParams.subject:
319
412
type: string
320
413
- actionType: email
321
- to: "{{job.contactEmail}}"
322
- subject: "[SciCat] {{job.jobParams.subject}}"
414
+ to: "{{{ job.contactEmail} }}"
415
+ subject: "[SciCat] {{{ job.jobParams.subject} }}"
323
416
bodyTemplate: demo_email.html
324
417
update:
325
418
auth: admin
@@ -415,49 +508,9 @@ jobs:
415
508
- finishedUnsuccessful
416
509
```
417
510
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
-
458
511
#### Email
459
512
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.
461
514
462
515
**Configuration**:
463
516
The *Mail service* must first be configured through environmental variables, as described in the [configuration](../configuration.md).
@@ -475,9 +528,9 @@ Example:
475
528
476
529
```yaml
477
530
- actionType: email
478
- to: "{{job.contactEmail}}"
531
+ to: "{{{ job.contactEmail} }}"
479
532
480
- subject: "[SciCat] Your {{job.type}} job was submitted successfully."
533
+ subject: "[SciCat] Your {{{ job.type} }} job was submitted successfully."
481
534
bodyTemplateFile: "path/to/job-template-file.html"
482
535
```
483
536
@@ -499,7 +552,7 @@ You can create your own template for the email's body, which should be a valid h
499
552
</head >
500
553
<body >
501
554
<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 ...
503
556
</p >
504
557
</body >
505
558
</html >
@@ -545,7 +598,7 @@ The action is added to the `actions` section of a job in `jobConfig.yaml` as fol
545
598
546
599
```yaml
547
600
- actionType: switch
548
- scope: request | datasets
601
+ phase: validate | perform | all
549
602
property: some.property
550
603
cases:
551
604
- match: exact value match
@@ -560,14 +613,18 @@ The action is added to the `actions` section of a job in `jobConfig.yaml` as fol
560
613
561
614
- `property` (required) Name of a variable to test against. This is specified as a
562
615
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
571
628
order. No "fall through" behavior is implemented; this can be approximated using yaml
572
629
anchors and aliases if needed. The following types of conditions are available:
573
630
- `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
579
636
- If no condition is included then the case will always match. This is useful for
580
637
adding a terminal 'default' condition (eg with an `error` action).
581
638
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
+
582
645
** Examples** :
583
646
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
585
648
to different statusCodes (this case could also be handled with handlebars templates):
586
649
587
650
```yaml
@@ -592,33 +655,22 @@ to different statusCodes (this case could also be handled with handlebars templa
592
655
auth: archiveManager
593
656
actions:
594
657
- actionType: switch
595
- scope: request
596
- property: statusCode
658
+ phase: perform
659
+ property: job . statusCode
597
660
cases:
598
661
- match: finishedSuccessful
599
662
actions:
600
663
- 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!"
603
666
bodyTemplateFile: retrieve-success .html
604
667
- actions:
605
668
- 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 } }}"
608
671
bodyTemplateFile: retrieve-failure .html
609
672
```
610
673
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
-
622
674
#### Error
623
675
624
676
Throw a custom HTTP error. This can be useful for testing or in combination with a
@@ -641,7 +693,7 @@ database changes.
641
693
#### Log
642
694
643
695
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 `),
645
697
but it can also be configured to log messages during initialization or when validating
646
698
an incoming job.
647
699
@@ -651,7 +703,7 @@ an incoming job.
651
703
- actionType: log
652
704
init: "Job initialized with params {{{ jsonify this }}}"
653
705
validate: "Request body received: {{{ jsonify this }}}"
654
- performJob : "Job saved: {{{ jsonify this }}}"
706
+ perform : "Job saved: {{{ jsonify this }}}"
655
707
```
656
708
657
709
All arguments are optional.
@@ -661,7 +713,7 @@ All arguments are optional.
661
713
section from jobConfig.yaml is available as a Handlebars context. Default: ""
662
714
- `validate` (optional): Log message to print when the job request is received. The
663
715
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.
665
717
The updated job object is available as a Handlebars context.
666
- Default : ` "Performing job for {{type}}"`
718
+ Default: `"Performing job for {{{ job . type } }}"`
667
719
{% endraw %}
0 commit comments