diff --git a/src/workerd/server/server.c++ b/src/workerd/server/server.c++ index 9e93e43de9c..c4e9ac4549e 100644 --- a/src/workerd/server/server.c++ +++ b/src/workerd/server/server.c++ @@ -964,6 +964,27 @@ kj::Own Server::makeDiskDirectoryService( // ======================================================================================= +class Server::InspectorServiceIsolateRegistrar final { +public: + InspectorServiceIsolateRegistrar() {} + ~InspectorServiceIsolateRegistrar(); + + void registerIsolate(kj::StringPtr name, Worker::Isolate* isolate); + + KJ_DISALLOW_COPY_AND_MOVE(InspectorServiceIsolateRegistrar); +private: + void attach(const Server::InspectorService* anInspectorService) { + *inspectorService.lockExclusive() = anInspectorService; + } + + void detach() { + *inspectorService.lockExclusive() = nullptr; + } + + kj::MutexGuarded inspectorService; + friend class Server::InspectorService; +}; + class Server::InspectorService final: public kj::HttpService, public kj::HttpServerErrorHandler { // Implements the interface for the devtools inspector protocol. // @@ -972,12 +993,26 @@ class Server::InspectorService final: public kj::HttpService, public kj::HttpSer public: InspectorService( kj::Timer& timer, - kj::HttpHeaderTable::Builder& headerTableBuilder) + kj::HttpHeaderTable::Builder& headerTableBuilder, + InspectorServiceIsolateRegistrar& theRegistrar) : timer(timer), headerTable(headerTableBuilder.getFutureTable()), server(timer, headerTable, *this, kj::HttpServerSettings { .errorHandler = *this - }) {} + }), + registrar(theRegistrar) { + theRegistrar.attach(this); + } + + ~InspectorService() { + KJ_IF_MAYBE(r, registrar) { + r->detach(); + } + } + + void invalidateRegistrar() { + registrar = nullptr; + } kj::Promise handleApplicationError( kj::Exception exception, kj::Maybe response) override { @@ -1040,6 +1075,7 @@ public: } } + KJ_LOG(INFO, kj::str("Unknown worker session [", id, "]")); return response.sendError(404, "Unknown worker session", responseHeaders); } @@ -1137,10 +1173,26 @@ private: kj::HttpHeaderTable& headerTable; kj::HashMap> isolates; kj::HttpServer server; - - friend class Registration; + kj::Maybe registrar; }; +Server::InspectorServiceIsolateRegistrar::~InspectorServiceIsolateRegistrar() { + auto lockedInspectorService = this->inspectorService.lockExclusive(); + if (lockedInspectorService != nullptr) { + auto is = const_cast(*lockedInspectorService); + is->invalidateRegistrar(); + } +} + +void Server::InspectorServiceIsolateRegistrar::registerIsolate(kj::StringPtr name, + Worker::Isolate* isolate) { + auto lockedInspectorService = this->inspectorService.lockExclusive(); + if (lockedInspectorService != nullptr) { + auto is = const_cast(*lockedInspectorService); + is->registerIsolate(name, isolate); + } +} + // ======================================================================================= class Server::WorkerService final: public Service, private kj::TaskSet::ErrorHandler, @@ -1908,7 +1960,7 @@ static kj::Maybe createBinding( "the schema?")); } -void startInspector(kj::StringPtr inspectorAddress, kj::StringPtr name, Worker::Isolate* isolate); +void startInspector(kj::StringPtr inspectorAddress, Server::InspectorServiceIsolateRegistrar& registrar); kj::Own Server::makeWorker(kj::StringPtr name, config::Worker::Reader conf, capnp::List::Reader extensions) { @@ -2011,8 +2063,8 @@ kj::Own Server::makeWorker(kj::StringPtr name, config::Worker:: // If we are using the inspector, we need to register the Worker::Isolate // with the inspector service. - KJ_IF_MAYBE(inspector, inspectorOverride) { - startInspector(*inspector, name, isolate.get()); + KJ_IF_MAYBE(isolateRegistrar, inspectorIsolateRegistrar) { + (*isolateRegistrar)->registerIsolate(name, isolate.get()); } auto script = isolate->newScript( @@ -2401,7 +2453,7 @@ kj::Promise Server::run(jsg::V8System& v8System, config::Config::Reader co auto listenPromise = listenOnSockets(config, headerTableBuilder, forkedDrainWhen); - // We should have registered all headers synchronously. This is important becaues we want to + // We should have registered all headers synchronously. This is important because we want to // be able to start handling requests as soon as the services are available, even if some other // services take longer to get ready. auto ownHeaderTable = headerTableBuilder.build(); @@ -2420,22 +2472,22 @@ void Server::startAlarmScheduler(config::Config::Reader config) { .attach(kj::mv(vfs)); } -void startInspector(kj::StringPtr inspectorAddress, kj::StringPtr name, Worker::Isolate* isolate) { +void startInspector(kj::StringPtr inspectorAddress, + Server::InspectorServiceIsolateRegistrar& registrar) { // --------------------------------------------------------------------------- // Configure inspector. // Configure and start the inspector socket. - kj::Thread thread([inspectorAddress, name, isolate](){ + kj::Thread thread([inspectorAddress, ®istrar](){ kj::AsyncIoContext io = kj::setupAsyncIo(); kj::HttpHeaderTable::Builder headerTableBuilder; // Create the special inspector service. - kj::Own inspectorService(kj::heap(io.provider->getTimer(), headerTableBuilder)); + auto inspectorService( + kj::heap(io.provider->getTimer(), headerTableBuilder, registrar)); auto ownHeaderTable = headerTableBuilder.build(); - inspectorService->registerIsolate(name, isolate); - // Configure and start the inspector socket. static constexpr uint DEFAULT_PORT = 9229; @@ -2521,6 +2573,14 @@ void Server::startServices(jsg::V8System& v8System, config::Config::Reader confi }); } + // If we are using the inspector, we need to register the Worker::Isolate + // with the inspector service. + KJ_IF_MAYBE(inspectorAddress, inspectorOverride) { + auto registrar = kj::heap(); + startInspector(*inspectorAddress, *registrar); + inspectorIsolateRegistrar = kj::mv(registrar); + } + // Second pass: Build services. for (auto serviceConf: config.getServices()) { kj::StringPtr name = serviceConf.getName(); diff --git a/src/workerd/server/server.h b/src/workerd/server/server.h index 134fa7dc5f2..68b7a7ae766 100644 --- a/src/workerd/server/server.h +++ b/src/workerd/server/server.h @@ -75,6 +75,7 @@ class Server: private kj::TaskSet::ErrorHandler { using ActorConfig = kj::OneOf; class InspectorService; + class InspectorServiceIsolateRegistrar; private: kj::Filesystem& fs; @@ -94,6 +95,7 @@ class Server: private kj::TaskSet::ErrorHandler { // code that parses strings from the config file. kj::Maybe inspectorOverride; + kj::Maybe> inspectorIsolateRegistrar; kj::Maybe> controlOverride; struct GlobalContext;