Object storage overview
Ce contenu n’est pas encore disponible dans votre langue.
The framework’s object-storage backend is an S3-compatible persistence layer. Two implementations ship:
| Backend | Use |
|---|---|
FilesystemObjectStorageBackend | Local files; dev + tests. |
S3ObjectStorageBackend | Anything S3-compatible (AWS S3, MinIO, R2, B2). |
Used by:
ObjectStorageDurableStateStore— durable state in cloud storage.ObjectStorageSnapshotStore— snapshots in cloud storage.
Built on a small interface (PUT / GET / DELETE / LIST + CAS support); both backends speak the same surface.
When to use it
Section titled “When to use it”| You should use object storage when… |
|---|
| You’re cloud-native and S3 (or similar) is your storage platform. |
| You want shared persistence across cluster nodes without running Cassandra. |
| You want server-side encryption via cloud KMS. |
| You want infinite scaling without managing storage capacity. |
For single-node deployments, SQLite is simpler. For high-throughput multi-node persistence, Cassandra is faster. Object storage sits in between — cloud-friendly, decent performance, lots of features.
A minimal example
Section titled “A minimal example”import { DurableStateOptions, ObjectStorageDurableStateStore, ObjectStorageDurableStateStoreOptions, S3ObjectStorageBackend, S3ObjectStorageOptions,} from 'actor-ts';
const s3ObjectStorageOptions = S3ObjectStorageOptions.create() .withRegion('eu-west-1') .withBucket('my-app-state');const backend = new S3ObjectStorageBackend(s3ObjectStorageOptions);
const objectStorageDurableStateStoreOptions = ObjectStorageDurableStateStoreOptions.create().withBackend(backend);const stateStore = new ObjectStorageDurableStateStore( objectStorageDurableStateStoreOptions,);
const durableStateOptions = DurableStateOptions.create<State>() .withPersistenceId(`cart-${userId}`) .withStore(stateStore) .withEmptyState(() => ({ items: [] }));const cart = system.spawnAnonymous(() => new Cart(durableStateOptions));Cart’s state lives in S3 under cart-<userId> as the object
key. Reads and writes go through the S3 API.
What gets stored
Section titled “What gets stored”Object keys follow a predictable layout:
state/ cart-user-42 # one object per persistenceId cart-user-43
snapshots/ account-42/ seq-100 # snapshots indexed by seqNr seq-200 seq-300The framework manages this layout; you don’t construct keys manually.
The interface
Section titled “The interface”interface ObjectStorageBackend { put(key: string, body: Uint8Array, options?: PutOptions): Promise<{ etag: string }>; get(key: string): Promise<Option<ObjectFetched>>; delete(key: string): Promise<void>; list(options: { prefix: string; limit?: number }): Promise<ObjectInfo[]>;}Small surface — fits AWS S3, MinIO, Cloudflare R2, Backblaze B2, Wasabi, etc. Most S3-compatible APIs match exactly.
CAS for optimistic concurrency
Section titled “CAS for optimistic concurrency”await backend.put('state/cart-42', body, { ifMatch: 'previous-etag',});ifMatch lets callers do compare-and-set writes — if the
current ETag differs, the put fails with
ObjectStorageConcurrencyError. Used by
ObjectStorageDurableStateStore to detect concurrent writers
without separate coordination.
ifNoneMatch: '*' is create-only — succeed only if the key
doesn’t exist yet.
Some older S3-compatible stores don’t honor these headers properly. The framework’s backend implementations throw clearly in that case rather than silently ignoring; check your provider’s CAS support before relying on it.
Backends
Section titled “Backends”Filesystem
Section titled “Filesystem”import { FilesystemObjectStorageBackend, FilesystemObjectStorageOptions } from 'actor-ts';
const filesystemObjectStorageOptions = FilesystemObjectStorageOptions.create().withDir('/var/lib/actor-ts');const backend = new FilesystemObjectStorageBackend( filesystemObjectStorageOptions,);Stores objects as files under rootDir. No network, no
S3 cost. Right for:
- Tests — same code path as production, with local files.
- Local dev — no Minio container required.
- Small single-node deployments — if you specifically want the object-storage interface without S3.
import { S3ObjectStorageBackend, S3ObjectStorageOptions } from 'actor-ts';
const s3ObjectStorageOptions = S3ObjectStorageOptions.create() .withRegion('eu-west-1') .withBucket('my-app-state') .withEndpoint('https://s3.eu-west-1.amazonaws.com') // optional override .withCredentials({ accessKeyId: process.env.AWS_ACCESS_KEY_ID!, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!, });const backend = new S3ObjectStorageBackend(s3ObjectStorageOptions);Works with any S3-compatible service. For non-AWS:
// MinIO:const s3ObjectStorageOptions = S3ObjectStorageOptions.create() .withRegion('us-east-1') .withBucket('my-bucket') .withEndpoint('http://minio:9000') .withForcePathStyle(true);new S3ObjectStorageBackend(s3ObjectStorageOptions);
// Cloudflare R2:const s3ObjectStorage2Options = S3ObjectStorageOptions.create() .withRegion('auto') .withBucket('my-bucket') .withEndpoint('https://<account-id>.r2.cloudflarestorage.com');new S3ObjectStorageBackend(s3ObjectStorage2Options);
// Backblaze B2:const s3ObjectStorage3Options = S3ObjectStorageOptions.create() .withRegion('us-west-002') .withBucket('my-bucket') .withEndpoint('https://s3.us-west-002.backblazeb2.com');new S3ObjectStorageBackend(s3ObjectStorage3Options);Optional features
Section titled “Optional features”| Feature | Page |
|---|---|
| Compression (gzip / zstd) | Compression |
| Encryption at rest (AES-GCM) | Encryption |
| Master-key rotation | Key rotation |
| Per-actor compression / encryption policies | Per-actor policies |
| Snapshot store backend | Snapshot store backend |
All optional — start without; layer on as needed.
Performance
Section titled “Performance”Rough numbers for S3:
- Put (small object): 20-50 ms.
- Get: 10-30 ms.
- Delete: 30-50 ms.
Filesystem backend: sub-millisecond.
Object-storage is slower than SQLite / Cassandra for single operations. Compensate with:
- Snapshot policies that bound recovery.
- CachedSnapshotStore decorator for read-through caching.
- Batching wherever the framework allows.
Where to next
Section titled “Where to next”- Compression — gzip / zstd at-rest compression.
- Encryption — AES-GCM encryption at rest.
- Snapshot store backend — snapshots in object storage.
- Durable state — the main consumer.
- Persistence overview — the bigger picture.
