Skip to content

Commit

Permalink
Add --experimental CLI flag, require it to enable experimental features.
Browse files Browse the repository at this point in the history
Specifically, the following features are considered experimental:
- Ephemeral objects (fka "colo-local actors").
- Any compatibility flag that doesn't have a default-on date assigned. We could consider creating a separate `$experimental` or `$stable` annotation instead of using presence/absence of a date, but I wanted to be cautious for now. (Incidentally, though, it looks like we should go ahead and assign dates to most of the flags that don't have them?)

I decided to use a CLI flag rather than a config flag in order to add resistance against using this in production, but we can consider finer-grained control if it proves warranted.
  • Loading branch information
kentonv committed Sep 25, 2022
1 parent 0744470 commit 6dd6738
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/workerd/io/compatibility-date-test.c++
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@ KJ_TEST("compatibility flag parsing") {
"supported by this server binary is \"", SUPPORTED_COMPATIBILITY_DATE, "\".")},
CompatibilityDateValidation::CODE_VERSION);

// Test experimental requirement using the durable_object_alarms flag since we know this flag
// is obsolete and will never have a date set.
expectCompileCompatibilityFlags("2020-01-01", {"durable_object_alarms"_kj}, "(obsolete14 = true)",
{"The compatibility flag durable_object_alarms is experimental and may break or be removed "
"in a future version of workerd. To use this flag, you must pass --experimental on the "
"command line."_kj},
CompatibilityDateValidation::CODE_VERSION);
expectCompileCompatibilityFlags("2020-01-01", {"durable_object_alarms"_kj}, "(obsolete14 = true)",
{}, CompatibilityDateValidation::CODE_VERSION_EXPERIMENTAL);

// Multiple errors.
expectCompileCompatibilityFlags("abcd",
{"formdata_parser_supports_files"_kj, "fetch_refuses_unknown_protocols"_kj,
Expand Down
8 changes: 8 additions & 0 deletions src/workerd/io/compatibility-date.c++
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ void compileCompatibilityFlags(kj::StringPtr compatDate, capnp::List<capnp::Text
auto parsedCompatDate = CompatDate::parse(compatDate, errorReporter);

switch (dateValidation) {
case CompatibilityDateValidation::CODE_VERSION_EXPERIMENTAL:
case CompatibilityDateValidation::CODE_VERSION:
if (KJ_ASSERT_NONNULL(CompatDate::parse(SUPPORTED_COMPATIBILITY_DATE)) < parsedCompatDate) {
errorReporter.addError(kj::str(
Expand Down Expand Up @@ -195,6 +196,13 @@ void compileCompatibilityFlags(kj::StringPtr compatDate, capnp::List<capnp::Text
// it redundant, because at a future date it won't be redundant, and someone could want to
// set the flag early to make sure they don't forget later.
}
if (dateValidation == CompatibilityDateValidation::CODE_VERSION &&
enableByFlag && !enableByDate && enableDate == nullptr) {
errorReporter.addError(kj::str(
"The compatibility flag ", enableFlagName, " is experimental and may break or be "
"removed in a future version of workerd. To use this flag, you must pass --experimental "
"on the command line."));
}

dynamicOutput.set(field, enableByFlag || (enableByDate && !disableByFlag));
}
Expand Down
4 changes: 4 additions & 0 deletions src/workerd/io/compatibility-date.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ enum class CompatibilityDateValidation {
// Allow dates up through the date specified by `supportedCompatibilityDate` in
// `compatiility-date.capnp`.

CODE_VERSION_EXPERIMENTAL,
// Like CODE_VERSION but permit the use of experimental flags, which is any flag that does not
// yet have a default-on date set.

CURRENT_DATE_FOR_CLOUDFLARE,
// Allow dates up to through the current date.
//
Expand Down
1 change: 1 addition & 0 deletions src/workerd/server/server-test.c++
Original file line number Diff line number Diff line change
Expand Up @@ -1290,6 +1290,7 @@ KJ_TEST("Server: Ephemeral Objects") {
]
))"_kj);

test.server.allowExperimental();
test.start();
auto conn = test.connect("test-addr");
conn.httpGet200("/",
Expand Down
17 changes: 15 additions & 2 deletions src/workerd/server/server.c++
Original file line number Diff line number Diff line change
Expand Up @@ -1243,7 +1243,9 @@ kj::Own<Server::Service> Server::makeWorker(kj::StringPtr name, config::Worker::
if (conf.hasCompatibilityDate()) {
compileCompatibilityFlags(conf.getCompatibilityDate(), conf.getCompatibilityFlags(),
featureFlags, errorReporter,
CompatibilityDateValidation::CODE_VERSION);
experimental
? CompatibilityDateValidation::CODE_VERSION_EXPERIMENTAL
: CompatibilityDateValidation::CODE_VERSION);
} else {
errorReporter.addError(kj::str("Worker must specify compatibiltyDate."));
}
Expand Down Expand Up @@ -1885,6 +1887,12 @@ kj::Promise<void> Server::run(jsg::V8System& v8System, config::Config::Reader co
Durable { kj::str(ns.getUniqueKey()) });
continue;
case config::Worker::DurableObjectNamespace::EPHEMERAL_LOCAL:
if (!experimental) {
reportConfigError(kj::str(
"Ephemeral objects (Durable Object namespaces with type 'ehpmeralLocal') are an "
"experimental feature which may change or go away in the future. You must run "
"workerd with `--experimental` to use this feature."));
}
serviceActorConfigs.insert(kj::str(ns.getClassName()), Ephemeral {});
continue;
}
Expand All @@ -1908,8 +1916,13 @@ kj::Promise<void> Server::run(jsg::V8System& v8System, config::Config::Reader co
reportConfigError(kj::str(
"Encountered unknown durableObjectStorage type in service \"", name,
"\". Was the config compiled with a newer version of the schema?"));

validDurableObjectStorage:
;
if (workerConf.hasDurableObjectUniqueKeyModifier()) {
// This should be implemented along with parameterized workers. It's not relevant
// otherwise, but let's make sure no one sets it accidentally.
KJ_UNIMPLEMENTED("durableObjectUniqueKeyModifier is not implemented yet");
}
}

actorConfigs.upsert(kj::str(name), kj::mv(serviceActorConfigs), [&](auto&&...) {
Expand Down
6 changes: 6 additions & 0 deletions src/workerd/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class Server: private kj::TaskSet::ErrorHandler {
kj::EntropySource& entropySource, kj::Function<void(kj::String)> reportConfigError);
~Server() noexcept(false);

void allowExperimental() { experimental = true; }
// Permit experimental features to be used. These features may break backwards compatibility
// in the future.

void overrideSocket(kj::String name, kj::Own<kj::ConnectionReceiver> port) {
socketOverrides.upsert(kj::mv(name), kj::mv(port));
}
Expand All @@ -57,6 +61,8 @@ class Server: private kj::TaskSet::ErrorHandler {
kj::EntropySource& entropySource;
kj::Function<void(kj::String)> reportConfigError;

bool experimental = false;

kj::HashMap<kj::String, kj::OneOf<kj::String, kj::Own<kj::ConnectionReceiver>>> socketOverrides;
kj::HashMap<kj::String, kj::String> directoryOverrides;
kj::HashMap<kj::String, kj::String> externalOverrides;
Expand Down
3 changes: 3 additions & 0 deletions src/workerd/server/workerd.c++
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,9 @@ public:
.addOption({'w', "watch"}, CLI_METHOD(watch),
"Watch configuration files (and server binary) and reload if they change. "
"Useful for development, but not recommended in production.")
.addOption({"experimental"}, [this]() { server.allowExperimental(); return true; },
"Permit the use of experimental features which may break backwards "
"compatibility in a future release.")
.callAfterParsing(CLI_METHOD(serve))
.build();
}
Expand Down

0 comments on commit 6dd6738

Please sign in to comment.