River jobs can record a JSON object as their “output” for use by other jobs or elsewhere in the application. Any JSON-encodable value can be recorded.
How to record job output
River provides a river.RecordOutput
function that can be called within a worker's Work
function to record output for the job:
type MyWorkerOutput struct {
CreatedResourceID string `json:"created_resource_id"`
}
// ...
func (w *MyWorker) Work(ctx context.Context, job *river.Job[MyJobArgs]) error {
// ... other job execution logic ...
// Now that the job has finished, record its output as a final step:
output := MyWorkerOutput{CreatedResourceID: "123"}
if err := river.RecordOutput(ctx, job, output); err != nil {
return err
}
return nil
}
The output is stored in the job's metadata under the "output"
key (rivertype.MetadataKeyOutput
). This does not involve an additional database query, as the metadata is updated as part of the asynchronous job completion process.
JSON marshalling happens inline and RecordOutput
will return an error if JSON serialization fails.
Only one output can be stored per job. If this function is called more than once, the output will be overwritten with the latest value. Once recorded, the output is stored regardless of the outcome of the execution attempt (success, error, panic, etc.).
Using with JobCompleteTx
This feature is also compatible with transactional job completion using JobCompleteTx
, however there is an important caveat. While a job's output can be recorded at any time during execution, it must be recorded before calling JobCompleteTx
in order for the output to be recorded as part of the same transaction.
Calling RecordOutput
after JobCompleteTx
has been called will still work, but there will be a window of time where the output is not yet recorded in the database on the completed job before it is later added asynchronously.
How to read job output
Once saved on the job row, the output can be read from a loaded river.JobRow
using the Output
method. The output is a []byte
of the JSON-encoded output value provided to RecordOutput
, so it must be unmarshalled to the appropriate type before use:
output := job.Output()
if output == nil {
// handle error
}
var myOutput MyWorkerOutput
if err := json.Unmarshal(output, &myOutput); err != nil {
// handle error
}
Performance and size considerations
The output is stored as part of the job row's metadata
column, which is a jsonb
type in Postgres. Take care to ensure that the encoded output payload size is not too large; the hard size limit is 32 MB, though it's recommended to keep it much smaller.