- Rust 70.6%
- Shell 21%
- C 8.4%
| crates | simple change to use notify instead of polling | |
| proto | updating proto for memory node | |
| tasks | matching rpc.rs to new proto | |
| .gitignore | sent it on the first go through, it works sort of | |
| Cargo.lock | matching rpc.rs to new proto | |
| Cargo.toml | moved to rpc instead of http, reused proto stuff from feather-virt | |
| LICENSE | Adding license and README note before repo is public | |
| README.md | matching rpc.rs to new proto | |
| TODO.md | updating proto for memory node | |
Coalescent Comptuting Prototypes
Inspired by Coalescent Computing.
A high-performance, asynchronous, (soon-to-be) distributed WebAssembly (Wasm) task executor node built in Rust. This platform uses Wasmtime and WASI to securely sandbox, schedule, and execute workloads with (sort of) granular resource tracking and epoch-based deadline guarantees.
Crate structure:
coalescent/
crates/
coalescent-interface/ # pure types + traits, no runtime deps
coalescent-executor/ # wasmtime, tokio, epoch management
coalescent-node/ # wires everything together, gRPC binary
Some Technical Notes
- Greedily pre-compiles registered binaries to reduce latency
- Caches registered and compiled binaries
- Structured error codes distinguishing between deadline exceeded, execution failure, and missing modules
- Node capability advertisement
- Startup orphan sweep
- Tasks left in
QueuedorRunningfrom a crashed process are markedFailedon restart
- Tasks left in
Getting Started
Prerequisites
- Rust Toolchain
- Clang (supporting target
wasm32-wasip1) - wasi-libc /
wasi-sysroot(for c compilation testing) grpcurlfor testing and interactionjqfor test scripts
Building
Compile the workspace directly from root directory:
cargo build
Running
RUST_LOG=info cargo run -p coalescent-node
The node will listen on :50051.
RPC API
RegisterModule
Upload a WASM binary. The node computes a SHA256 content hash as the module ID, persists the binary, and eagerly compiles it. Uploading the same binary twice is idempotent.
WASM_B64=$(base64 -w 0 program.wasm 2>/dev/null || base64 program.wasm)
grpcurl -plaintext \
-import-path ./proto \
-proto ./proto/coalescent.proto \
-d "{\"wasm_binary\": \"$WASM_B64\"}" \
localhost:50051 coalescent.CoalescentExecutor/RegisterModule
Response:
{
"moduleId": "1f18a4b7341b5cda412b2599c98ec560ef274132a1aee6ba...",
"alreadyExisted": false
}
alreadyExisted: true means the binary was already cached, so compilation was
skipped and the call is a no-op.
ExecuteTask
Enqueue a task and stream status updates. The stream emits one event per status
transition and closes when the task reaches a terminal state (completed or
failed).
epoch_deadline is optional. The node applies a sensible default if omitted.
grpcurl -plaintext \
-import-path ./proto \
-proto ./proto/coalescent.proto \
-d "{\"module_id\": \"$MODULE_ID\", \"input_data\": \"\"}" \
localhost:50051 coalescent.CoalescentExecutor/ExecuteTask
Event stream:
{"taskId": "c6a29c4c-...", "status": "TASK_STATUS_QUEUED"}
{"taskId": "c6a29c4c-...", "status": "TASK_STATUS_RUNNING"}
{"taskId": "c6a29c4c-...", "status": "TASK_STATUS_COMPLETED", "output": "SGVsbG8...", "stderr": "", "elapsedMs": "53"}
On failure, a structured error field is included:
{
"taskId": "c6a29c4c-...",
"status": "TASK_STATUS_FAILED",
"error": {
"code": "TASK_ERROR_DEADLINE_EXCEEDED",
"message": "epoch deadline exceeded"
}
}
Error codes:
| Code | Meaning |
|---|---|
TASK_ERROR_MODULE_NOT_FOUND |
Module ID not registered |
TASK_ERROR_DEADLINE_EXCEEDED |
Task ran past its epoch deadline |
TASK_ERROR_EXECUTION_FAILED |
WASM trap or runtime error |
TASK_ERROR_NODE_RESTARTED |
Task was orphaned by a node crash |
Decoding output:
echo "$OUTPUT" | jq -r 'select(.output != null) | .output' | base64 -d
GetNodeInfo
Returns the node's stable identity and hardware capabilities.
grpcurl -plaintext \
-import-path ./proto \
-proto ./proto/coalescent.proto \
-d '{}' \
localhost:50051 coalescent.CoalescentExecutor/GetNodeInfo
Response:
{
"nodeId": "e3b0c442-...",
"queueDepth": 2,
"caps": {
"cpuCores": 8,
"memoryBytes": "16424108032",
"arch": "x86_64"
}
}
Task Lifecycle
Submitted -> Queued -> Running -> Completed -> Failed
Tasks communicate via stdin/stdout. A WASM module reads its input from stdin and writes results to stdout. stderr is captured separately and included in the final status event.
Compiling a C Task
clang --target=wasm32-wasip1 \
--sysroot=/usr/share/wasi-sysroot \
program.c -o program.wasm \
-nodefaultlibs -lc
See the tasks/ directory for examples.