Hosting Workers
A custom task runs on a worker: your own deployable, separate from the Fleans engine images. It is a plain .NET generic host (or a process in any language) that connects to the Fleans API over gRPC. It does not join the Orleans cluster, so it needs no clustering, reminder or streaming settings, only the API’s URL.
The fleans-custom-worker-example
repository is a GitHub template with the minimum shape for that deployable.
Quick start
Section titled “Quick start”Click Use this template on the example repo, or via gh CLI:
gh repo create my-worker --template nightBaker/fleans-custom-worker-example --publiccd my-workerFleans__ExternalTaskWorker__EngineUrl="http://localhost:8081" dotnet run --project src/Fleans.CustomWorkerHostThat gives you a worker serving the rest-call task type from the template’s pre-registered
Fleans.Plugins.RestCaller package.
Swap in your own handler (see Writing custom tasks)
and ship the resulting container image alongside the engine.
Why a separate process
Section titled “Why a separate process”-
Operational isolation. A misbehaving handler (memory leak, runaway HTTP call) only kills its own worker, never the engine.
-
Independent release cadence. Deploy, scale and roll back a worker without touching the engine. Different teams can each ship their own.
-
No engine dependencies.
Fleans.ExternalTasks.Sdkhas no Orleans dependency, direct or transitive. Verify the closure with:Terminal window dotnet list package --include-transitive | grep -iE 'fleans|orleans'You should see
Fleans.ExternalTasks.Sdkand your plugin packages, and nothing with Orleans in its name.
Configuration
Section titled “Configuration”The worker’s settings are under Fleans:ExternalTaskWorker; the
table is in External Workers. Only EngineUrl is required.
- Point it at any API process.
Combined,Coreand REST-onlyApisilos all serve workers. - Authentication. When the API has
Authentication:Authorityset, setAccessTokenorAccessTokenProvider. - Protocol.
UseGrpcWebdefaults totrue(HTTP/1.1, passes any proxy). Setfalsefor native gRPC over HTTP/2.
Connection lifecycle
Section titled “Connection lifecycle”- Startup order doesn’t matter. A worker retries until the API answers, every
ReconnectDelay(5 seconds by default). - When the connection drops, the worker cancels its running handlers and subscribes again. Those tasks are delivered again, possibly to another worker, so handlers must be idempotent.
- When a worker crashes without closing the connection, the engine stops picking it once its lease expires (
Fleans:ExternalTasks:WorkerTimeout, 45 seconds by default). - While no worker is connected, tasks of that type wait, for a limited time. Start workers before running processes that use them, and read the delivery contract if they can be away for more than a few minutes.
Scaling
Section titled “Scaling”Run as many replicas as you need: each task goes to one connected worker of its type, picked at
random, and each process runs up to MaxConcurrentTasks tasks at once. Give each process a unique
WorkerName; the default ({machine}-{pid}) is.
Adding a handler
Section titled “Adding a handler”- Write your handler by deriving from
ExternalTaskHandler(see Writing custom tasks). - Publish it as a NuGet package, or
<ProjectReference>it from your monorepo. - Register it in
Program.cswithservices.AddExternalTaskHandler<T>(...), or the package’s own extension such asservices.AddRestCallerPlugin(). - Rebuild and redeploy the worker container.
Versioning
Section titled “Versioning”Fleans.ExternalTasks.Sdk and the ready-made plugin packages share the engine’s version track.
Workers talk to the engine over a versioned protocol (fleans.externaltasks.v1) rather than
sharing its cluster, so they don’t have to be redeployed in lockstep. Check the release notes when a
release changes the protocol.
Cross-references
Section titled “Cross-references”fleans-custom-worker-example— the GitHub template repo.- Custom Tasks concept page — the BPMN-side picture.
- External Workers — protocol, delivery contract, other languages.