Skip to content

Commit c79c780

Browse files
authored
Tweaks to tasks documentation for clarity and consistency (#522)
2 parents 85c36ac + 65e3cb2 commit c79c780

File tree

4 files changed

+125
-122
lines changed

4 files changed

+125
-122
lines changed

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ declare global {
129129

130130
/**
131131
* A list of file extensions (in priority order) that Graphile Worker
132-
* should attempt to import directly when loading task executors from the
133-
* file system.
132+
* should attempt to import as Node modules when loading task executors from
133+
* the file system.
134134
*
135135
* @defaultValue `[".js", ".cjs", ".mjs"]`
136136
*/

src/interfaces.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export type AddJobsFunction = <TSpecs extends readonly AddJobsJobSpec[]>(
134134

135135
export interface Helpers {
136136
/**
137-
* A Logger instance.
137+
* A `Logger` instance.
138138
*/
139139
logger: Logger;
140140

@@ -145,30 +145,30 @@ export interface Helpers {
145145
withPgClient: WithPgClient;
146146

147147
/**
148-
* Adds a job into our queue.
148+
* Adds a job into the Graphile Worker queue.
149149
*/
150150
addJob: AddJobFunction;
151151

152152
/**
153-
* Adds multiple jobs into our queue.
153+
* Adds multiple jobs into the Graphile Worker queue.
154154
*/
155155
addJobs: AddJobsFunction;
156156
}
157157

158158
export interface JobHelpers extends Helpers {
159159
/**
160-
* A Logger instance, scoped to this job.
160+
* A `Logger` instance, scoped to this job.
161161
*/
162162
logger: Logger;
163163

164164
/**
165-
* The currently executing job.
165+
* The whole, currently executing job.
166166
*/
167167
job: Job;
168168

169169
/**
170-
* Get the queue name of the give queue ID (or the currently executing job if
171-
* no queue id is specified).
170+
* Get the queue name of the given queue ID (or of the currently executing job
171+
* if no queue ID is specified).
172172
*/
173173
getQueueName(queueId?: number | null): PromiseOrDirect<string | null>;
174174

@@ -181,7 +181,8 @@ export interface JobHelpers extends Helpers {
181181
): Promise<QueryResult<R>>;
182182

183183
/**
184-
* An AbortSignal that will be triggered when the job should exit.
184+
* An `AbortSignal` that will be triggered when the job should exit. It is used,
185+
* for example, for a graceful shutdown request.
185186
*
186187
* @experimental
187188
*/

website/docs/config.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ Here are the options under the `worker` key as defined by
177177
}
178178
```
179179

180+
See the
181+
[Graphile Worker source](https://github.com/jcgsville/worker/blob/85c36ac4e684a3a782fc528dca95c8ba6177fa8a/src/config.ts#L13)
182+
for the default `worker` options set by the default Worker Preset.
183+
180184
### worker.concurrentJobs
181185

182186
Type: `number | undefined`
@@ -211,7 +215,8 @@ resolved.)
211215
Type: `string[] | undefined`
212216

213217
A list of file extensions (in priority order) that Graphile Worker should
214-
attempt to import directly when loading task executors from the file system.
218+
attempt to import as Node modules when loading task executors from the file
219+
system.
215220

216221
### worker.getQueueNameBatchDelay
217222

website/docs/tasks.md

Lines changed: 108 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -26,48 +26,32 @@ failure and the task is rescheduled using an exponential-backoff algorithm.
2626

2727
Each task function is passed two arguments:
2828

29-
- `payload` &mdash; the (JSON) payload you passed when calling
29+
- `payload` &mdash; the JSON payload you passed when calling
3030
`graphile_worker.add_job(...)` in the database, or `addJob(...)` via the JS
3131
API
32-
- `helpers` (see [`helpers`](#helpers) below) &mdash; an object containing:
33-
- `logger` &mdash; a scoped [Logger](/docs/library/logger) instance, to aid
34-
tracing/debugging
35-
- `job` &mdash; the whole job (including `uuid`, `attempts`, etc) &mdash; you
36-
shouldn't need this
37-
- `getQueueName()` &mdash; get the name of the queue the job is in (may or may
38-
not return a promise - recommend you always `await` it)
39-
- `abortSignal` &mdash; could be an `AbortSignal`, or `undefined` if not
40-
supported by this release of worker; if set, use this to abort your task
41-
early on graceful shutdown (can be passed to a number of asynchronous
42-
Node.js methods)
43-
- `abortPromise` &mdash; if present, a promise that will reject when
44-
`abortSignal` aborts; convenient for exiting your task when the abortSignal
45-
fires: `Promise.race([abortPromise, doYourThing()])`
46-
- `withPgClient` &mdash; a helper to use to get a database client
47-
- `query(sql, values)` &mdash; a convenience wrapper for
48-
`withPgClient(pgClient => pgClient.query(sql, values))`
49-
- `addJob` &mdash; a helper to schedule a job
32+
- `helpers` see [`helpers`](#helpers) below
5033

5134
:::warning Important
5235

53-
Your jobs must wait for all asynchronous work to be completed before returning,
54-
otherwise we might think they were successful prematurely. Every promise that a
55-
task executor triggers must be `await`-ed; task executors _should not_ create
56-
&ldquo;untethered&rdquo; promises.
36+
Your task executors must wait for all asynchronous work for a job to be
37+
completed before returning, otherwise Graphile Worker might think they were
38+
successful prematurely. Every promise that a task executor triggers must be
39+
`await`-ed; task executors _should not_ create &ldquo;untethered&rdquo;
40+
promises.
5741

5842
:::
5943

6044
:::tip
6145

62-
We automatically retry the job if it fails, so it&apos;s often sensible to split
63-
a large job into multiple smaller jobs, this also allows them to run in parallel
64-
resulting in faster execution. This is particularly important for tasks that are
65-
not idempotent (i.e. running them a second time will have extra side effects)
66-
&mdash; for example sending emails.
46+
Graphile Worker automatically retries the job if it fails, so it&apos;s often
47+
sensible to split a large job into multiple smaller jobs, this also allows them
48+
to run in parallel resulting in faster execution. This is particularly important
49+
for tasks that are not idempotent (i.e. running them a second time will have
50+
extra side effects) &mdash; for example sending emails.
6751

6852
:::
6953

70-
## Example task executors
54+
## Example JS task executors
7155

7256
```js title="tasks/task_1.js"
7357
module.exports = async (payload) => {
@@ -82,44 +66,39 @@ module.exports = async (payload, helpers) => {
8266
};
8367
```
8468

85-
## The `tasks/` folder
69+
## The task directory
8670

87-
When you run `graphile-worker`, it will look in the current directory for a
88-
folder called `tasks`, and it will recursively look for files suitable to run as
89-
tasks. File names excluding the extension and folder names must only use
90-
alphanumeric characters, underscores and dashes (`/^[A-Za-z0-9_-]+$/`) to be
91-
recognized. Graphile Worker will then attempt to load the file as a task
92-
executor; the task identifier for this will be all the folders and the file name
93-
(excluding the extension) joined with `/` characters; e.g.
94-
`tasks/send_notification.js` would get the identifier `send_notification` and
95-
`tasks/users/emails/verify.js` would get the identifier `users/emails/verify`.
96-
How the file is loaded as a task executor will depend on the file in question
97-
and the plugins you have loaded.
71+
When you run Graphile Worker, it will look in the configured
72+
[`taskDirectory`](./config#workertaskdirectory) for files suitable to run as
73+
tasks.
9874

99-
```
100-
current directory
101-
├── package.json
102-
├── node_modules
103-
└── tasks
104-
├── send_notification.js
105-
├── generate_pdf.js
106-
└── users
107-
├── congratulate.js
108-
└── emails
109-
├── verify.js
110-
└── send_otp.js
111-
```
75+
File names excluding the extension and folder names must only use alphanumeric
76+
characters, underscores, and dashes (`/^[A-Za-z0-9_-]+$/`) to be recognized.
77+
78+
Graphile Worker will then attempt to load the file as a task executor; the task
79+
identifier for this task will be all the folders and the file name (excluding
80+
the extension) joined with `/` characters:
81+
82+
- `${taskDirectory}/send_notification.js` would get the task identifier
83+
`send_notification`.
84+
- `${taskDirectory}/users/emails/verify.js` would get the task identifier
85+
`users/emails/verify`.
86+
87+
How the file is loaded as a task executor will depend on the specific file and
88+
the plugins you have loaded.
11289

11390
## Loading JavaScript files
11491

115-
Out of the box, Graphile Worker will load `.js`, `.cjs` and `.mjs` files using
116-
the `import()` function. If the file is a CommonJS module then Worker will
117-
expect `module.exports` to be the task executor function; if the file is an
118-
ECMAScript module (ESM) then Worker will expect the default export to be the
119-
task executor function.
92+
With the default preset, Graphile Worker will load `.js`, `.cjs` and `.mjs`
93+
files as task executors using the `import()` function. If the file is a CommonJS
94+
module, then Worker will expect `module.exports` to be the task executor
95+
function; if the file is an ECMAScript module (ESM) then Worker will expect the
96+
default export to be the task executor function.
12097

121-
Via plugins, support for other ways of loading task files can be added; look at
122-
the source code of `LoadTaskFromJsPlugin.ts` for inspiration.
98+
You can add support for other ways of loading task executors via plugins; look
99+
at the source code of
100+
[`LoadTaskFromJsPlugin.ts`](https://github.com/graphile/worker/blob/main/src/plugins/LoadTaskFromJsPlugin.ts)
101+
for inspiration.
123102

124103
### Loading TypeScript files
125104

@@ -130,19 +109,19 @@ TypeScript files to JS and then have Graphile Worker load the JS files.
130109

131110
:::
132111

133-
To load TypeScript files directly as tasks (without precompilation), one way is
134-
to:
112+
To load TypeScript files directly as task executors (without precompilation),
113+
one way is to do the following:
135114

136-
1. install `ts-node`,
137-
2. add `".ts"` to the `worker.fileExtensions` list in your `graphile.config.ts`,
138-
3. run Graphile Worker with the environmental variable
115+
1. Install `ts-node`.
116+
2. Add `".ts"` to the `worker.fileExtensions` list in your preset.
117+
3. Run Graphile Worker with the environment variable
139118
`NODE_OPTIONS="--loader ts-node/esm"` set.
140119

141120
```ts title="Example graphile.config.ts"
142-
import type { GraphileConfig } from "graphile-config";
143-
import type {} from "graphile-worker";
121+
import { WorkerPreset } from "graphile-worker";
144122

145123
const preset: GraphileConfig.Preset = {
124+
extends: [WorkerPreset],
146125
worker: {
147126
connectionString: process.env.DATABASE_URL,
148127
concurrentJobs: 5,
@@ -167,16 +146,21 @@ This feature is currently experimental.
167146
:::
168147

169148
If you're running on Linux or Unix (including macOS) then if Graphile Worker
170-
finds an executable file inside of `tasks/` it will create a task executor for
171-
it. When a task of this kind is found, Graphile Worker will execute the file
172-
setting the relevant environmental variables and passing in the payload
149+
finds an executable file inside of the `taskDirectory` it will create a task
150+
executor for it. When a task of this kind is found, Graphile Worker will execute
151+
the file with the relevant environment variables and pass in the payload
173152
according to the encoding. If the executable exits with code `0` then Graphile
174-
Worker will see this as success, all other exit codes are seen as failure.
153+
Worker will see this as success. All other exit codes are seen as failure.
175154

176-
### Environmental variables
155+
This feature is added via the
156+
[LoadTaskFromExecutableFilePlugin plugin](https://github.com/graphile/worker/blob/main/src/plugins/LoadTaskFromExecutableFilePlugin.ts)
157+
in the default
158+
[Worker Preset](https://github.com/graphile/worker/blob/main/src/preset.ts).
159+
160+
### Environment variables
177161

178162
- `GRAPHILE_WORKER_PAYLOAD_FORMAT` &mdash; the encoding that Graphile Worker
179-
uses to pass the payload to the binary. Currently this will be the string
163+
used to pass the payload to the binary. Currently this will be the string
180164
`json`, but you should check this before processing the payload in case the
181165
format changes.
182166
- `GRAPHILE_WORKER_TASK_IDENTIFIER` &mdash; the identifier for the task this
@@ -198,40 +182,69 @@ Worker will see this as success, all other exit codes are seen as failure.
198182

199183
In the JSON payload format, your binary will be fed via stdin
200184
`JSON.stringify({payload})`; for example, if you did
201-
`addJob('myScript', {mol: 42})` then your `myScript` task would be sent
185+
`addJob('my_script', {mol: 42})` then your `my_script` task would be sent
202186
`{"payload":{"mol":42}}` via stdin.
203187

204188
## Handling batch jobs
205189

206-
If the payload is an array, then _optionally_ your task may choose to return an
207-
array of the same length, the entries in which are promises. Should any of these
208-
promises reject, then the job will be re-enqueued, but the payload will be
209-
overwritten to only contain the entries associated with the rejected promises
210-
&mdash; i.e. the successful entries will be removed.
190+
If the payload is an array, then _optionally_ your task executor may choose to
191+
return an array of the same length, the entries in which are promises. Should
192+
any of these promises reject, then the job will be re-enqueued, but the payload
193+
will be overwritten to only contain the entries associated with the rejected
194+
promises &mdash; i.e. the successful entries will be removed.
211195

212196
## `helpers`
213197

198+
### `helpers.abortPromise`
199+
200+
**Experimental**
201+
202+
This is a promise that will reject when [`abortSignal`](#helpersabortsignal)
203+
aborts. This makes it convenient for exiting your task when the abortSignal
204+
fires: `Promise.race([abortPromise, doYourAsyncThing()])`.
205+
206+
### `helpers.abortSignal`
207+
208+
**Experimental**
209+
210+
This is a `AbortSignal` that will be triggered when the job should exit early.
211+
It is used, for example, for a graceful shutdown request. `AbortSignal`s can be
212+
passed to a number of asynchronous Node.js methods like
213+
[`http.request()`](https://nodejs.org/api/http.html#httprequesturl-options-callback).
214+
215+
### `helpers.addJob()`
216+
217+
See [`addJob`](/library/add-job.md).
218+
219+
### `helpers.addJobs()`
220+
221+
See [`addJobs`](/library/add-job.md#add-jobs).
222+
223+
### `helpers.getQueueName()`
224+
225+
Get the queue name of the given queue ID (or of the currently executing job if
226+
no queue ID is specified). This function may or may not return a promise. We
227+
recommend that you always `await` it.
228+
229+
### `helpers.job`
230+
231+
The whole, currently executing job, including `uuid`, `attempts`, etc.
232+
214233
### `helpers.logger`
215234

216-
So that you may redirect logs to your preferred logging provider, we have
217-
enabled you to supply your own logging provider. Overriding this is currently
218-
only available in library mode (see [Logger](/library/logger.md)). We then wrap
219-
this logging provider with a helper class to ease debugging; the helper class
220-
has the following methods:
235+
A logger instance scoped to this job. See [Logger](./library/logger)
221236

222-
- `error(message, meta?)`: for logging errors, similar to `console.error`
223-
- `warn(message, meta?)`: for logging warnings, similar to `console.warn`
224-
- `info(message, meta?)`: for logging informational messages, similar to
225-
`console.info`
226-
- `debug(message, meta?)`: to aid with debugging, similar to `console.log`
227-
- `scope(additionalScope)`: returns a new `Logger` instance with additional
228-
scope information
237+
### `helpers.query()`
238+
239+
This is a convenience wrapper for
240+
`withPgClient(pgClient => pgClient.query(sql, values))`. See
241+
[`withPgClient()`](#helperswithpgclient)
229242

230243
### `helpers.withPgClient()`
231244

232-
`withPgClient` gets a `pgClient` from the pool, calls
233-
`await callback(pgClient)`, and finally releases the client and returns the
234-
result of `callback`. This workflow can make testing your tasks easier.
245+
`withPgClient` gets a `pgClient` from the pool that Graphile Worker uses. It
246+
calls `await callback(pgClient)`, and finally releases the client and returns
247+
the result of `callback`. This workflow can make testing your tasks easier.
235248

236249
Example:
237250

@@ -249,19 +262,3 @@ keeping transactions open may decrease Graphile Worker&apos;s performance due to
249262
increasing contention over the pool of database clients.
250263

251264
:::
252-
253-
### `helpers.addJob()`
254-
255-
```ts
256-
await helpers.addJob(identifier, payload, options);
257-
```
258-
259-
See [`addJob`](/library/add-job.md).
260-
261-
### `helpers.addJobs()`
262-
263-
```ts
264-
await helpers.addJobs(specs, preserveRunAt);
265-
```
266-
267-
See [`addJobs`](/library/add-job.md#add-jobs).

0 commit comments

Comments
 (0)