orbit-runtime 0.4.0

ORBIT durable workflow runtime: event-sourced engine, SQLite/PostgreSQL persistence, HTTP and gRPC worker protocols
Documentation
// ORBIT worker protocol, version 1.
//
// This file is the canonical, language-neutral definition of the messages
// exchanged between the ORBIT runtime and workers (RFC-0001 §8).
//
// Two bindings share these messages and semantics (see ../../../README.md):
//
//  * HTTP/JSON: every RPC maps to `POST /v1/<path>` with the proto3 JSON
//    mapping of its messages. The official SDKs use this binding.
//  * gRPC: `orbit server --grpc-addr 127.0.0.1:7234` serves `WorkerService`
//    over HTTP/2, with the same credentials (`authorization: Bearer <token>`
//    metadata), per-worker identities, TLS and mutual TLS as the HTTP API.
//
// `google.protobuf.Value` carries numbers as doubles; the runtime converts
// whole numbers within ±2^53 back to integers, so `Int` fields round-trip.
//
// Workers *pull* work (long-polling `PollTask`) instead of hosting a server:
// they need no inbound ports, work behind NAT, and apply natural backpressure.

syntax = "proto3";

package orbit.worker.v1;

import "google/protobuf/struct.proto";

service WorkerService {
  // POST /v1/workers/register
  rpc RegisterWorker(RegisterWorkerRequest) returns (RegisterWorkerResponse);
  // POST /v1/workers/heartbeat — also delivers cooperative cancellations.
  rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
  // POST /v1/workers/poll — long poll. When no task arrived within wait_ms,
  // HTTP answers 204 and gRPC returns an ExecuteTaskRequest with an empty token.
  rpc PollTask(PollTaskRequest) returns (ExecuteTaskRequest);
  // POST /v1/tasks/complete
  rpc CompleteTask(CompleteTaskRequest) returns (TaskResultAck);
  // POST /v1/tasks/fail
  rpc FailTask(FailTaskRequest) returns (TaskResultAck);
  // POST /v1/workers/unregister — in-flight tasks are redelivered elsewhere.
  rpc UnregisterWorker(UnregisterWorkerRequest) returns (UnregisterWorkerResponse);
}

message TaskContract {
  string task_name = 1;          // e.g. "payments.charge"
  string contract_version = 2;   // must equal the `task` version in the workflow
}

message RegisterWorkerRequest {
  string worker_id = 1;          // stable identity, e.g. "payments-7f9c"
  string runtime = 2;            // matched against `using <language>`
  repeated TaskContract contracts = 3;
  string sdk = 4;                // informational, e.g. "orbit-python/0.1.0"
}

message RegisterWorkerResponse {
  bool accepted = 1;
  string worker_session_id = 2;
  uint64 heartbeat_interval_ms = 3;
  uint64 session_timeout_ms = 4;  // silence longer than this = worker lost
  repeated string warnings = 5;   // e.g. contract versions no workflow uses
}

message HeartbeatRequest {
  string worker_session_id = 1;
}

message HeartbeatResponse {
  bool accepted = 1;
  repeated string cancel = 2;     // task tokens the worker should stop
}

message PollTaskRequest {
  string worker_session_id = 1;
  uint64 wait_ms = 2;             // max 60000
}

// A task assignment (RFC-0001 §8.3).
message ExecuteTaskRequest {
  string token = 1;               // identifies this delivery; echo it in the result
  string execution_id = 2;
  string workflow = 3;
  string workflow_version = 4;
  string step_id = 5;             // "<step>" or "compensate:<step>"
  string task_name = 6;
  string contract_version = 7;
  google.protobuf.Value input = 8;
  string idempotency_key = 9;     // stable across retries and redeliveries
  uint32 attempt = 10;            // 1-based; redeliveries keep the number
  bool redelivery = 11;           // previous delivery's outcome is unknown
  optional uint64 deadline_ms = 12;  // absolute epoch ms for this attempt
  optional uint64 timeout_ms = 13;
}

message CompleteTaskRequest {
  string token = 1;
  google.protobuf.Value output = 2;  // validated against the task's output schema
}

message FailTaskRequest {
  string token = 1;
  string error_code = 2;          // e.g. "CARD_DECLINED"
  string error_message = 3;
  bool retryable = 4;             // false fails the step regardless of policy
  google.protobuf.Value details = 5;
}

message TaskResultAck {
  bool accepted = 1;
  string reason = 2;              // why a result was ignored (duplicate, stale, contract)
}

message UnregisterWorkerRequest {
  string worker_session_id = 1;
}

message UnregisterWorkerResponse {
  bool accepted = 1;
}