Skip to content

Commit

Permalink
Merge pull request #1426 from cloudflare/dominik/autogates
Browse files Browse the repository at this point in the history
Implements autogate framework.
  • Loading branch information
dom96 authored Nov 22, 2023
2 parents fe10ee1 + 49e1bf1 commit 754bc02
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/workerd/server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ wd_cc_binary(
tags = ["no-arm64"],
visibility = ["//visibility:public"],
deps = [
":autogate",
":server",
":workerd-meta_capnp",
":workerd_capnp",
Expand Down Expand Up @@ -118,6 +119,14 @@ wd_cc_capnp_library(
],
)

wd_cc_library(
name = "autogate",
srcs = ["autogate.c++"],
hdrs = ["autogate.h"],
visibility = ["//visibility:public"],
deps = ["@capnp-cpp//src/kj:kj", ":workerd_capnp"],
)

[kj_test(
src = f,
deps = [
Expand Down
55 changes: 55 additions & 0 deletions src/workerd/server/autogate.c++
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2017-2023 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0
#include "autogate.h"

namespace workerd::server {

kj::StringPtr KJ_STRINGIFY(AutogateKey key) {
switch (key) {
case AutogateKey::TEST_WORKERD:
return "test-workerd"_kj;
case AutogateKey::NumOfKeys:
KJ_FAIL_ASSERT("NumOfKeys should not be used in getName");
}
}

Autogate::Autogate(capnp::List<config::Config::Autogate, capnp::Kind::STRUCT>::Reader autogates) {
for (auto autogate : autogates) {
if (!autogate.hasName()) {
continue;
}
auto name = autogate.getName();
if (!name.startsWith("workerd-autogate-")) {
continue;
}
auto sliced = name.slice(17);

// Parse the gate name into a AutogateKey.
for (AutogateKey i = AutogateKey(0); i < AutogateKey::NumOfKeys; i = AutogateKey((int)i + 1)) {
if (kj::str(i) == sliced) {
gates.insert(i, autogate.getEnabled());
break;
}
}
}
}

bool Autogate::isEnabled(AutogateKey key) const {
return gates.find(key).orDefault(false);
}

kj::Maybe<Autogate> globalAutogate;
void initAutogate(config::Config::Reader config) {
if (!config.hasAutogates()) {
return;
}

globalAutogate = Autogate(config.getAutogates());
}

void initAutogate(capnp::List<config::Config::Autogate, capnp::Kind::STRUCT>::Reader autogates) {
globalAutogate = Autogate(autogates);
}

} // namespace workerd::server
51 changes: 51 additions & 0 deletions src/workerd/server/autogate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2017-2023 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0
#pragma once

#include "kj/debug.h"
#include <kj/map.h>
#include <workerd/server/workerd.capnp.h>

namespace workerd::server {

// Workerd-specific list of autogate keys (can also be used in internal repo).
enum class AutogateKey {
TEST_WORKERD,
NumOfKeys // Reserved for iteration.
};

// This class allows code changes to be rolled out independent of full binary releases. It enables
// specific code paths to be gradually rolled out via our internal tooling.
// See the equivalent file in our internal repo for more details.
//
// Workerd-specific gates can be added here.
//
// Usage:
//
// #include <workerd/server/autogate.h>
// Autogate::isEnabled(AutogateKey::YOUR_FEATURE_KEY)
//
// When making structural changes here, ensure you align them with autogate.h in workerd.
class Autogate {

public:
Autogate(capnp::List<config::Config::Autogate, capnp::Kind::STRUCT>::Reader autogates);

bool isEnabled(AutogateKey key) const;

private:
kj::HashMap<AutogateKey, bool> gates;
};

// Retrieves the name of the gate.
//
// When adding a new gate, add it into this method as well.
kj::StringPtr KJ_STRINGIFY(AutogateKey key);

extern kj::Maybe<Autogate> globalAutogate;

void initAutogate(config::Config::Reader config);
void initAutogate(capnp::List<config::Config::Autogate, capnp::Kind::STRUCT>::Reader autogates);

} // namespace workerd::server
5 changes: 5 additions & 0 deletions src/workerd/server/workerd.c++
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <openssl/rand.h>
#include <workerd/io/compatibility-date.capnp.h>
#include <workerd/io/supported-compatibility-date.capnp.h>
#include <workerd/server/autogate.h>

#ifdef WORKERD_EXPERIMENTAL_ENABLE_WEBGPU
#include <workerd/api/gpu/gpu.h>
Expand Down Expand Up @@ -846,6 +847,10 @@ public:
}
}
}

KJ_IF_SOME(c, config) {
initAutogate(c);
}
}

void setConstName(kj::StringPtr name) {
Expand Down
9 changes: 9 additions & 0 deletions src/workerd/server/workerd.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ struct Config {
extensions @3 :List(Extension);
# Extensions provide capabilities to all workers. Extensions are usually prepared separately
# and are late-linked with the app using this config field.

autogates @4 :List(Autogate);
# A list of gates and a corresponding value of whether they are enabled.
# These are used to gate features/changes in workerd and in our internal repo. See the equivalent
# config definition in our internal repo for more details.
struct Autogate {
enabled @0 :Bool;
name @1 :Text;
}
}

# ========================================================================================
Expand Down

0 comments on commit 754bc02

Please sign in to comment.