Skip to content

Virtufin Workers

A C#/.NET 10 worker source package for the Virtufin WorkManager. Each worker is a self-contained nupkg consumable by the WM's DotNetDllEngine (managed, in-process) or NativeDllEngine (NativeAOT, in-process), with the engine selected at CreateWorker time by the MIME type.

The canonical worker is HttpGetWorker — it performs an outbound HTTP GET on every triggering CloudEvent and publishes the response as a new CloudEvent. It demonstrates the full pattern: a shared handler logic, a managed shim, a NativeAOT shim, content-addressed versioning, and the two packaging modes.

Key Features

Feature Description
Shared handler logic One .cs file compiled into both managed and AOT projects — the bulk of the worker code is identical regardless of which engine loads it.
Three packaging modes managed (lib/net10.0/.dll), native (runtimes//native/lib.so), or both (single nupkg containing both layouts).
Content-addressed versioning The build script produces a deterministic, byte-stable nupkg whose filename encodes the SHA-256 short hash. Re-publishes are no-ops when source is unchanged.
NativeAOT-ready The AOT csproj sets <PublishAot>true</PublishAot> + per-RID <ObjCopyName>; the build script runs dotnet publish inside the dotnet-crossbuild:10 Docker image (clang + cross-binutils).
IGatewayClient abstraction For a worker that does call other services — see the Worker Author Guide's EchoWorker example — await gateway.InvokeAsync(...) routes to managed gRPC or the host's C-ABI gateway callback. HttpGetWorker itself makes no backend gateway calls, so it needs none of this wiring — a deliberate contrast worth knowing before you assume every worker needs it.

Worker Layout

HttpGetWorker/
├── config/
│   └── config.json                 # script_url_template, topics, mime_type, etc.
├── src/
│   ├── Virtufin.Worker.HttpGetWorker.Managed/
│   │   ├── *.csproj                 # OutputType=Library, <PackageId>=...
│   │   ├── HttpGetWorker.cs          # managed shim
│   │   ├── HttpGetWorkerLogic.cs     # shared logic
│   │   └── HttpGetResponseCodec.cs   # response CloudEvent shaping
│   └── Virtufin.Worker.HttpGetWorker.Native/
│       ├── *.Native.csproj          # <PublishAot>, <RuntimeIdentifiers>=linux-x64,linux-arm64
│       └── HttpGetWorkerNative.cs    # AOT shim with [UnmanagedCallersOnly]
├── tests/
│   └── Virtufin.Worker.HttpGetWorker.Tests/
├── scripts/
│   ├── build_managed.py            # dotnet publish the managed csproj
│   ├── build_aot.py                # dotnet publish -r <RID> --publish-aot
│   ├── build_both.py               # produce a nupkg with BOTH layouts
│   ├── publish.py                  # push the nupkg to the Gitea NuGet feed
│   ├── create_worker.py            # deploy via CreateWorker
│   ├── start_worker.py             # start a deployed worker
│   └── delete_worker.py            # remove a deployed worker
└── @common/                        # shared with the @common scripts in the repo root
    └── scripts/
        ├── build_managed.py        # the canonical managed build (shared helpers)
        ├── build_aot.py            # the canonical AOT build
        └── publish.py              # the canonical publish

Build & Run

The three packaging modes:

# 1. managed-only (lib/net10.0/*.dll)
python3 scripts/build_managed.py
python3 scripts/publish.py

# 2. NativeAOT-only (runtimes/<rid>/native/lib*.so) — requires Docker
python3 scripts/build_aot.py
python3 scripts/publish.py

# 3. both — single nupkg supporting either engine
python3 scripts/build_both.py
python3 scripts/publish.py

Then deploy and run:

# Create + start against the local WM + API + Dapr
python3 scripts/create_worker.py --api-client-host localhost --api-client-port 5002
python3 scripts/start_worker.py --id <worker_id>

Trigger it by publishing a CloudEvent on command.httpgetworker whose data is {"url": "https://example.com/data"} — see the README for the full configuration surface.

Get Started

  • Overview — What workers are and how the WM loads them
  • Getting Started — Build, publish, and run HttpGetWorker end-to-end
  • Worker Author Guide — Author a new worker in the recommended shape
  • Engines — DotNetDll vs NativeDll: how each loads, how the IGatewayClient routes
  • Packaging Modes — managed / native / both, and which to pick