genroc

    docs / Guides / Operating

    Custom worker

    Learn how to connect an external worker to genroc.

    Mark a task as external and genroc will create a queue of waiting tasks, which you can poll and process with your own worker.

    When to use

    The queue + worker architecture is suitable for resource-intensive processing. It protects your system from being overwhelmed: if there are too many tasks at once, they simply wait in the queue on genroc's side.

    If the work is lightweight and it's more about timing or providing data, it's better to expose a simple REST endpoint and use the fetch action.

    Basic concept

    Genroc doesn't know about your worker. You simply mark a task as external, and your worker asks genroc: "Do you have any work? If yes, I claim it."

    For this, there is the /api/external-tasks/claim endpoint. You must specify which process and task you want to claim.

    Give your worker the worker permission. That's all it needs.

    Example:

    {
      "worker_id": "worker-1",
      "limit": 5,
      "process": "expense-approval",
      "task": "approval",
      "lease_ms": 30000
    }

    Each worker has to have a unique id, so genroc can distinguish who claimed what. limit is how many tasks you want to claim, so here you can receive up to 5 tasks per claim. process is the process name and task is the task id.

    Leasing

    A task is leased to you for the time you've requested. If your worker doesn't provide a result in that time or doesn't renew the lease, genroc allows a different worker to claim it instead (only_once tasks will fail with external.lost in this case).

    Claim response

    {
      "items": [
        {
          "token": "550e8400-e29b-41d4-a716-446655440000.6.1",
          "process": "expense-approval",
          "version": 2,
          "task": "approval",
          "external_input": {
            "amount": 420,
            "submitter": "alice"
          },
          "waiting_since": "2026-09-25T09:12:00Z",
          "deadline": "2026-09-26T09:12:00Z"
        }
      ]
    }

    The most important fields are external_input, which is the input passed into the external action, and the unique token, which you need when submitting the result (and when renewing).

    deadline tells the worker when the work needs to be finished. It comes from the timeout field (the timeout also includes time spent in the queue).

    objects field

    If external_input contained large values, they are null in it and listed in the item's objects field, with paths starting at external_input. Fetch each one with GET /api/objects/{ref}, parse its data (it is JSON text) and put it back at its path.

    Read more in the next chapter.

    Resolving the task

    Once your worker has finished, use the /api/external-tasks/resolve endpoint to submit the result:

    {
      "token": "550e8400-e29b-41d4-a716-446655440000.6.1",
      "result": {
        "approved": true
      }
    }

    If the work ended with an error, you can submit the error this way:

    {
      "token": "550e8400-e29b-41d4-a716-446655440000.6.1",
      "error": {
        "code": "over_budget",
        "message": "Amount exceeds the submitter's limit",
        "data": { "limit": 300 }
      }
    }

    The result is validated against result_schema, and the error code and data are validated against the raises field (code and message are always required).

    Renewing leases

    If your worker can run for a longer time, you should use genroc's lease renewal. Make leases e.g. 30s and renew them e.g. every 10s. This lets genroc know that the worker is alive and the work is advancing (a bit like a heartbeat).

    For renewing, there is the /api/external-tasks/renew endpoint, which accepts a list of tokens for the tasks you want to renew.

    Cancelled/lost leases

    The renew endpoint lets you know if a task is no longer worth working on. This can happen when the process is cancelled or the lease is lost.

    You can use this to stop the work before it finishes to avoid wasting resources.

    Releasing a task

    If your worker is not able to finish the task and you want it to be picked up by a different worker as soon as possible, you can explicitly release the task with the /release endpoint.

    Reusable tasks tied to workers

    Workers are tied to a specific process and task, so if you want to make this reusable, create a child process and make the other processes call it. This allows you to specify a typed API. This is also how TypeScript evaluation works.