diff --git a/src/workerd/api/actor-state.c++ b/src/workerd/api/actor-state.c++ index a01db994a7d..742aa2572d3 100644 --- a/src/workerd/api/actor-state.c++ +++ b/src/workerd/api/actor-state.c++ @@ -888,6 +888,33 @@ void DurableObjectStorage::disableReplicas() { return cache->disableReplicas(); } +jsg::Promise DurableObjectStorage::configureReadReplication(jsg::Lock& js, + ReadReplicationOptions options) { + auto& context = IoContext::current(); + auto traceContext = context.makeUserTraceSpan("durable_object_storage_configure_read_replication"_kjc); + + if (maybePrimary != kj::none) { + JSG_FAIL_REQUIRE(Error, "replica Durable Objects cannot call configureReadReplication()."); + } + + bool enabled = false; + KJ_IF_SOME(m, options.mode) { + if (m == "auto"_kj) { + enabled = true; + } else if (m != "disabled"_kj) { + JSG_FAIL_REQUIRE(TypeError, "configureReadReplication() called with unknown mode setting."); + } + } else { + JSG_FAIL_REQUIRE(TypeError, "configureReadReplication() called without mode setting."); + } + + auto promise = cache->configureReadReplication(ActorCacheInterface::ReadReplicationOptions{ + .enabled = enabled, + }); + + return context.awaitIo(js, kj::mv(promise)); +} + jsg::Optional> DurableObjectStorage::getPrimary(jsg::Lock& js) { KJ_IF_SOME(primary, maybePrimary) { return primary.addRef(); diff --git a/src/workerd/api/actor-state.h b/src/workerd/api/actor-state.h index 28cefb9eb3e..4168e3d3a51 100644 --- a/src/workerd/api/actor-state.h +++ b/src/workerd/api/actor-state.h @@ -276,14 +276,31 @@ class DurableObjectStorage: public jsg::Object, public DurableObjectStorageOpera // // Once a Durable Object instance calls `ensureReplicas`, all subsequent calls will be no-ops, // making it idempotent, unless `disableReplicas` has been called between `ensureReplicas` calls. + // + // Deprecated: See configureReadReplication. void ensureReplicas(); // Arrange to disable replicas for this Durable Object. // // If replicas have never been created, this is a no-op. Similar to `ensureReplicas`, repeated // calls are no-ops unless `ensureReplicas` re-enabled the replicas. + // + // Deprecated: See configureReadReplication. void disableReplicas(); + struct ReadReplicationOptions { + jsg::Optional mode; + + JSG_STRUCT(mode); + JSG_STRUCT_TS_OVERRIDE(DurableObjectReadReplicationOptions { mode: "auto" | "disabled"; }); + }; + + // Arrange to change replica settings for this Durable Object. + // + // Must be called with a mode of "auto" or "disabled". Repeat calls that set the same settings are + // idempotent. + jsg::Promise configureReadReplication(jsg::Lock& js, ReadReplicationOptions options); + jsg::Optional> getPrimary(jsg::Lock& js); JSG_RESOURCE_TYPE(DurableObjectStorage, CompatibilityFlags::Reader flags) { @@ -314,6 +331,7 @@ class DurableObjectStorage: public jsg::Object, public DurableObjectStorageOpera if (flags.getReplicaRouting()) { JSG_METHOD(ensureReplicas); JSG_METHOD(disableReplicas); + JSG_METHOD(configureReadReplication); } JSG_TS_OVERRIDE({ @@ -749,7 +767,8 @@ class DurableObjectState: public jsg::Object { #define EW_ACTOR_STATE_ISOLATE_TYPES \ api::ActorState, api::DurableObjectState, api::DurableObjectTransaction, \ - api::DurableObjectStorage, api::DurableObjectStorage::TransactionOptions, \ + api::DurableObjectStorage, api::DurableObjectStorage::ReadReplicationOptions, \ + api::DurableObjectStorage::TransactionOptions, \ api::DurableObjectStorageOperations::ListOptions, \ api::DurableObjectStorageOperations::GetOptions, \ api::DurableObjectStorageOperations::GetAlarmOptions, \ diff --git a/src/workerd/io/actor-cache.h b/src/workerd/io/actor-cache.h index b58a0ff98f2..d499451d43a 100644 --- a/src/workerd/io/actor-cache.h +++ b/src/workerd/io/actor-cache.h @@ -293,6 +293,14 @@ class ActorCacheInterface: public ActorCacheOps { virtual void disableReplicas() { JSG_FAIL_REQUIRE(Error, "This Durable Object's storage back-end does not support replication."); } + + struct ReadReplicationOptions { + kj::Maybe enabled; + }; + + virtual kj::Promise configureReadReplication(ReadReplicationOptions) { + JSG_FAIL_REQUIRE(Error, "This Durable Object's storage back-end does not support replication."); + } }; // An in-memory caching layer on top of ActorStorage.Stage RPC interface. diff --git a/types/generated-snapshot/experimental/index.d.ts b/types/generated-snapshot/experimental/index.d.ts index 0d465249549..87367e26089 100755 --- a/types/generated-snapshot/experimental/index.d.ts +++ b/types/generated-snapshot/experimental/index.d.ts @@ -766,6 +766,12 @@ interface DurableObjectStorage { readonly primary?: DurableObjectStub; ensureReplicas(): void; disableReplicas(): void; + configureReadReplication( + options: DurableObjectReadReplicationOptions, + ): Promise; +} +interface DurableObjectReadReplicationOptions { + mode: "auto" | "disabled"; } interface DurableObjectListOptions { start?: string; diff --git a/types/generated-snapshot/experimental/index.ts b/types/generated-snapshot/experimental/index.ts index f29bd13ac03..cd1ac7bde65 100755 --- a/types/generated-snapshot/experimental/index.ts +++ b/types/generated-snapshot/experimental/index.ts @@ -768,6 +768,12 @@ export interface DurableObjectStorage { readonly primary?: DurableObjectStub; ensureReplicas(): void; disableReplicas(): void; + configureReadReplication( + options: DurableObjectReadReplicationOptions, + ): Promise; +} +export interface DurableObjectReadReplicationOptions { + mode: "auto" | "disabled"; } export interface DurableObjectListOptions { start?: string;