Per-actor policies
このコンテンツはまだ日本語訳がありません。
The object-storage backend can have store-level defaults for compression + encryption. But sometimes specific actors need different settings:
- A sensitive actor needs encryption (others don’t).
- A large-state actor benefits from high-level zstd (others use gzip).
- A small-state actor opts out of compression.
Override per-actor by implementing the compression() /
encryption() methods:
class SensitiveActor extends DurableStateActor<Command, State> { protected encryption() { return { mode: 'client-aes256-gcm' as const, masterKeys: sensitiveKeyRing, info: 'acme/prod/sensitive/v1', }; }
protected compression() { return { algorithm: 'gzip' as const, level: 9 }; }}The framework calls these on each persist/load and applies the returned config.
Default vs override
Section titled “Default vs override”// Store-level config — applies to every actor unless overridden:const objectStorageDurableStateStoreOptions = ObjectStorageDurableStateStoreOptions.create() .withBackend(backend) .withCompression({ algorithm: 'gzip', level: 6 }) .withEncryption({ mode: 'client-aes256-gcm', masterKeys: defaultKeyRing, info: 'acme/prod/durable-state/v1' });const store = new ObjectStorageDurableStateStore(objectStorageDurableStateStoreOptions);
// Per-actor: overrideclass MyActor extends DurableStateActor<...> { protected compression() { return { algorithm: 'none' as const }; } // encryption() not overridden → uses defaultKeyRing}Each method is independently overridable:
- Return your own config → that config applies.
- Don’t override → store’s default applies.
- Return
undefinedfrom the method → also store’s default.
Use cases
Section titled “Use cases”Per-actor encryption
Section titled “Per-actor encryption”class CreditCardActor extends DurableStateActor<...> { protected encryption() { // Separate key ring AND a separate HKDF context for PCI scope. return { mode: 'client-aes256-gcm' as const, masterKeys: pciKeyRing, info: 'acme/prod/pci/v1', }; }}
class GenericActor extends DurableStateActor<...> { // No override → uses store default (no encryption, or generic keyRing)}PCI / HIPAA / GDPR scope: data classified as sensitive uses a separate master key from non-sensitive. Compromise of one keyRing doesn’t expose the other.
Per-actor compression
Section titled “Per-actor compression”class ChatTranscriptActor extends DurableStateActor<...> { // Large text state — high-level zstd wins meaningfully protected compression() { return { algorithm: 'zstd' as const, level: 19 }; }}
class CounterActor extends DurableStateActor<...> { // Tiny state — compression overhead exceeds savings protected compression() { return { algorithm: 'none' as const }; }}Match the compression to the data shape. Default gzip is a safe middle ground; per-actor tuning extracts more.
What happens on persist
Section titled “What happens on persist”DurableStateActor.persist(state) ↓serializer.toBinary(state) → JSON or CBOR bytes ↓this.compression() → applies if not 'none' ↓this.encryption() → applies if set ↓backend.put(key, ciphertext, options)The framework looks up the actor’s overrides at each persist — so even if you change the override values dynamically (rare), new writes use new settings.
What happens on load
Section titled “What happens on load”DurableStateActor.preStart ↓backend.get(key) → framed ATS1 body ↓read the ATS1 manifest → encrypted flag set? → decrypt (key version from the manifest byte) ↓read the ATS1 manifest → compression flag → decompress ↓serializer.fromBinary → stateReads use the self-describing ATS1 manifest carried in the
body, not the actor’s current overrides. An object encrypted
under pciKeyRing is decrypted via pciKeyRing whether or not
the actor’s current encryption() says so.
This means: rotating an actor’s policy doesn’t break old data as long as the necessary keys / algorithms are available.
Migration when changing policies
Section titled “Migration when changing policies”// Old: no encryption.// New: encryption under pciKeyRing.class CreditCardActor extends DurableStateActor<...> { protected encryption() { return { mode: 'client-aes256-gcm' as const, masterKeys: pciKeyRing, info: 'acme/prod/pci/v1', }; }}Old (unencrypted) reads work — no metadata → plaintext path. New writes encrypt. Eventually:
- A re-encryption sweep filtered to this actor’s persistenceIds migrates the rest.
See key rotation.
Working with the snapshot store
Section titled “Working with the snapshot store”class Account extends PersistentActor<Command, Event, State> { // Per-actor compression for snapshots: override compression() { return { algorithm: 'zstd' as const }; }
// Per-actor encryption for snapshots: override encryption() { return { mode: 'client-aes256-gcm' as const, masterKeys: accountKeyRing, info: 'acme/prod/snapshot/v1', }; }}Same methods apply when the snapshot store is backed by object-storage. Persistent actors and durable-state actors both honor them.
Where to next
Section titled “Where to next”- Object storage overview — the bigger picture.
- Compression — algorithm + level details.
- Encryption — encryption setup.
- Snapshot store backend — for snapshots in object storage.
