Workers can be small functions or dedicated worker types, depending on the language. Function workers are useful for short tasks and prototyping.
Functions as workers
Defining a job normally involves a pair of structs — a JobArgs implementation containing job arguments, and a worker struct providing a Work definition. When prototyping, or where a job is involved that requires only a trivial definition, the worker struct can be omitted by wrapping a function with WorkFunc:
type WorkFuncArgs struct { Message string `json:"message"`}
func (WorkFuncArgs) Kind() string { return "work_func" }
...
workers := river.NewWorkers()river.AddWorker(workers, river.WorkFunc(func(ctx context.Context, j *river.Job[WorkFuncArgs]) error { fmt.Printf("Message: %s", j.Args.Message) return nil}))See the WorkFunc example for complete code.
Worker structs are generally preferable for better organization and testability, but WorkFunc can be handy as a more concise alternative depending on the situation.
Pass a kind and a block to River::Workers#add to register a worker without a class:
workers = River::Workers.new
workers.add(:message) do |job| puts "Message: #{job.args.fetch('message')}"endRegister an async function with Workers::add_fn:
async fn work(_context: riverqueue::WorkContext, job: riverqueue::Job<MessageArgs>) -> Result<riverqueue::WorkOutcome, riverqueue::BoxError>{ println!("Message: {}", job.args.message); Ok(riverqueue::WorkOutcome::Complete)}
let mut workers = riverqueue::Workers::new();workers.add_fn(work)?;TypeScript workers are functions registered with Workers.add:
const message = defineJob({ kind: "message", schema: z.object({ message: z.string() }),});
const workers = new Workers().add(message, async ({ job }) => { console.log("Message:", job.args.message);});