Skip to content

Quickstart ​

You start the server, run the hello example worker, invoke its Task, and read the Run.

You need Go 1.26, make, and Docker for PostgreSQL 18. Runcoil runs its tools through go run at pinned versions, so nothing installs globally.

Start the server ​

Clone the server repository, start PostgreSQL, create the tables, and start the server.

sh
git clone https://github.com/runcoil/runcoil.git
cd runcoil
make dc-up          # PostgreSQL 18 on port 5432
make run-migrate    # create the tables; running it again changes nothing
make run-runcoil    # the server on port 7070, with the token dev-token

The server now listens on port 7070. dev-token is for local work only. The server has no default token and refuses to start without one.

TIP

If the server stops at start with relation "schedules" does not exist, the tables are missing. Run make run-migrate.

Start a worker ​

Open a second terminal. Clone the Go SDK anywhere. The server and the SDK do not need sibling directories.

sh
git clone https://github.com/runcoil/runcoil-go.git
cd runcoil-go
go run ./examples/hello    # worker ID "hello", one Task "hello"

The worker connects to http://localhost:7070 with the token dev-token. It reads RUNCOIL_ENDPOINT and RUNCOIL_TOKEN if you set them. When it registers, it logs a line like this:

text
level=INFO msg="worker started" worker_id=hello

The server logs that the worker registered. Leave both terminals running.

Invoke the Task ​

In a third terminal, invoke the Task. The input and the output are JSON, sent as base64.

sh
curl -s -X POST http://localhost:7070/runcoil.v1.RunService/Invoke \
  -H 'Authorization: Bearer dev-token' -H 'Content-Type: application/json' \
  -d '{"workerId":"hello","taskId":"hello","input":"eyJuYW1lIjoiQWRhIn0=","idempotencyKey":"hello-1"}'
# {"runId":"..."}

eyJuYW1lIjoiQWRhIn0= is {"name":"Ada"}. The idempotencyKey is required. If you send the same key and input again, the server returns the first Run instead of creating another. Use a new key for a new Run.

The answer holds the ID of the new Run. The worker logs that it handled the Run:

text
level=INFO msg=greeted run_id=<run id> attempt=1 name=Ada

Read the Run ​

Pass the ID from the answer to WaitRun. The call returns when the Run finishes.

sh
curl -s -X POST http://localhost:7070/runcoil.v1.RunService/WaitRun \
  -H 'Authorization: Bearer dev-token' -H 'Content-Type: application/json' \
  -d '{"runId":"<run id>","includeSteps":true}'

With includeSteps set, the answer lists the Steps of the Run. The hello handler has one Step, greet.

The output of the Run is base64 JSON. Decode it to see the result:

sh
echo 'eyJncmVldGluZyI6ImhlbGxvLCBBZGEifQ==' | base64 -d
# {"greeting":"hello, Ada"}

If the answer has timedOut set to true, the Run was still going when the server stopped waiting. Send the same WaitRun call again.

Invoke from Go ​

The Go SDK has the same calls. Client.Invoke creates a Run, and Client.WaitRun waits for it. The invoke example uses them against the onboarding example, which is a worker with the worker ID accounts. Start that worker in another terminal:

sh
go run ./examples/onboarding    # worker ID "accounts", Task "create-account"

Then run the invoke program from the SDK checkout in a third terminal:

sh
go run ./examples/invoke

On success, the program prints the account ID and the welcome email ID.

Stop the worker ​

Press Ctrl-C in the worker terminal. The worker drains its running handlers for up to 30 seconds, then exits.

Next ​

Runcoil is pre-release. The API may change before 1.0.