Skip to content

v0.2.0

Latest

Choose a tag to compare

@github-actions github-actions released this 12 Aug 22:54
Immutable release. Only release title and notes can be modified.
3f22aed

celld v0.2.0 changes three foundations: how cells share memory, how their state replicates, and how a fleet stays available when its object store fails or slows.

Isolates and memory:

  • Resident cells share isolates and run turn by turn on a shared pool. v0.1.0 held one OS thread and one isolate for each cell.
  • A resident cell costs ~471 KB against ~3.4 MB in v0.1.0, measured linear to 2,500 resident cells (~1.2 GB) on one node. Memory no longer limits the resident population; admission and RSS shedding set the limit.
  • A handler that awaits I/O releases its isolate between turns, so co-resident cells cannot stall each other.
  • celld reclaims empty cell heaps and reuses retired isolate slots, so a long-lived node cannot leak isolates.
  • jemalloc is the global allocator.

Two listeners:

  • celld now separates the data plane from the control plane. The public listener (--listen) serves only your Worker's routes and /__celld/health. A new internal listener (--internal-listen) carries everything else: the operator API (/state, /shutdown) and all node-to-node peer traffic. Keep the internal port on a private network.
  • A public listener on a non-loopback address requires an explicit internal listener. --advertise names the internal address, and celld diagnose probes peers at that address.

Replication and compaction:

  • celld compacts many small level-0 replication objects into additive level-1 blocks (LTX v0.5.2 block format). Compaction is on by default and never deletes a source object.
  • A takeover of a write-heavy cell reads tens of objects instead of thousands. In one measured case, a cell with 4,096 durable writes restored from 42 objects and 0.6 MB instead of 4,116 objects and 19 MB, 3.8 times faster.
  • A restore downloads the objects in its plan concurrently, under one ceiling for the whole node.
  • A takeover pins the exact point in the replicated history that it restored from. celld never restores data that a fenced former owner uploads after that point, so a cell's history cannot fork and a failed write cannot reappear after a failover.
  • Compaction runs off the request path with a bounded duty cycle. A node that restarts with a large uncompacted backlog drains it without blocking durable writes.
  • celld and Litestream v0.5.16 can read both block and frame files. Litestream v0.5.11 can read only frame files.

Availability under storage faults:

  • The time that remains on the last renewed lease bounds each lease renewal attempt, so one hung conditional write can no longer use the whole authority window. In a test that silently dropped all established storage connections for 20 seconds, a v0.1.0-class node fenced; a v0.2.0 node kept serving.
  • The core event loop owns the lease timer on a dedicated thread. Restores, compaction, and diagnostics cannot delay it.
  • celld logs each lease attempt at start and at completion, so a storage hang is distinguishable from a timer failure.

Shutdown and restart:

  • SIGTERM starts a graceful drain. The drain hands each cell to a peer directly, so takeover does not wait for the lease TTL.
  • POST /shutdown?handoff=preserve on the internal listener prepares a same-node restart. The replacement process resumes its local cell databases and performs no owner or replica reads.
  • The drain waits for its ownership release writes and bounds each connection, so one idle connection cannot use the full deadline.
  • The process exits without unwinding. This fixes a crash when a warm node stops.

Storage backends:

  • A gs:// bucket selects Cloud Storage's generation-based compare-and-swap and authenticates with Application Default Credentials.
  • A bucket can take a key prefix, so several independent fleets can share one bucket without collisions.

Workers surface:

  • Wasm modules deploy and load as compiled WebAssembly.Module values. A workers-rs example shows the path, and older nodes refuse the new wasm-v1 deployment feature at deploy time.
  • A new RPC example exercises entrypoints, callbacks, RpcTarget returns, and promise pipelining end to end. Cross-isolate stubs remain limited to single method calls on named entrypoints.
  • Web Crypto and node:crypto expand: asymmetric import and export (SPKI, PKCS#8, JWK, PEM), generateKey, P-384 and P-521, Ed25519 and X25519, ECDH derivation, AES-CBC and AES-CTR, DigestStream, timingSafeEqual, and one-shot sign and verify.
  • setWebSocketAutoResponse answers ping-style messages without waking the cell.

OpenTelemetry support (off by default):

  • CELLD_OTEL=1 turns on OpenTelemetry traces and logs with no collector required: celld writes them directly to the bucket as Parquet under a telemetry/ prefix, and DuckDB can query them.
  • A standard OTLP/HTTP collector is the alternative sink (CELLD_OTEL_SINK=otlp), and the usual OTEL_* variables apply.
  • W3C trace context propagates end to end: celld adopts an inbound traceparent, and fetch spans, cell dispatch, and console logs join the caller's trace.

Overload:

  • A stateless request that finds every slot held now waits, bounded by CELLD_ADMISSION_WAIT_MS, instead of an immediate refusal. At overload, the node no longer spends its capacity on refusals.
  • CPU-based shedding is removed. RSS shedding (on by default since v0.1.0) is the only pressure trigger.

Configuration:

  • celld validates every variable at startup, and an invalid value stops startup. Boolean variables accept only 0 or 1.
  • Removed: CELLD_WORKERS, CELLD_MAX_COHOSTED, CELLD_MAX_CPU_PERCENT, CELLD_RESIDENT_LOW_WATER (ignored since v0.1.0), CELLD_VALIDATE, and the /js route.
  • Renamed: CELLD_HIBERNATIONS is now CELLD_EVICTIONS.
  • Changed: CELLD_IDLE_EVICT_S no longer defaults to 300; idle eviction is off unless set. CELLD_UNSAFE_PUBLIC_ADVERTISE takes 1, not on.
  • Added, among others: CELLD_INTERNAL_ADDR, CELLD_MAX_STATELESS_ISOLATES, CELLD_ADMISSION_WAIT_MS, CELLD_LTX_COMPACTION, CELLD_SHUTDOWN_DRAIN_MS, and the CELLD_OTEL family.

Upgrading from v0.1.0:

  • A v0.1.0 command line with a non-loopback --listen refuses to start until an explicit --internal-listen is added.
  • The upgrade must not be a rolling update: stop every v0.1.0 node, then start the v0.2.0 nodes. v0.2.0 advertises the internal listener, which v0.1.0 peers cannot follow, and writes compacted block objects, which a v0.1.0 reader cannot restore. A fleet must not mix the two versions.