Skip to content
File

Blob: src/workerd/io/worker.h

cpp1129 lines
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6// Classes to manage lifetime of workers, scripts, and isolates.
7 
8#include <workerd/io/actor-cache.h> // because we can't forward-declare ActorCache::SharedLru.
9#include <workerd/io/actor-id.h>
10#include <workerd/io/compatibility-date.capnp.h>
11#include <workerd/io/container.capnp.h>
12#include <workerd/io/frankenvalue.h>
13#include <workerd/io/io-channels.h>
14#include <workerd/io/io-timers.h>
15#include <workerd/io/observer.h>
16#include <workerd/io/request-tracker.h>
17#include <workerd/io/trace.h>
18#include <workerd/io/worker-interface.h>
19#include <workerd/io/worker-source.h>
20#include <workerd/jsg/async-context.h>
21#include <workerd/jsg/jsg.h>
22#include <workerd/jsg/modules-new.h>
23#include <workerd/jsg/modules.h>
24#include <workerd/util/strong-bool.h>
25#include <workerd/util/weak-refs.h>
26 
27#include <kj/compat/http.h>
28#include <kj/mutex.h>
29 
30namespace v8 {
31class BackingStore;
32class Isolate;
33} // namespace v8
34 
35namespace workerd {
36 
37WD_STRONG_BOOL(StructuredLogging);
38WD_STRONG_BOOL(ProcessStdioPrefixed);
39 
40namespace api {
41class DurableObjectState;
42class DurableObjectStorage;
43class ServiceWorkerGlobalScope;
44struct ExportedHandler;
45struct CryptoAlgorithm;
46struct QueueExportedHandler;
47class WebSocket;
48class WebSocketRequestResponsePair;
49class CacheContext;
50class ExecutionContext;
51namespace pyodide {
52struct ArtifactBundler_State;
53KJ_DECLARE_NON_POLYMORPHIC(ArtifactBundler_State);
54} // namespace pyodide
55} // namespace api
56 
57class IsolateLimitEnforcer;
58enum class UncaughtExceptionSource;
59class VirtualFileSystem;
60 
61class ThreadContext;
62class IoContext;
63class InputGate;
64class OutputGate;
65 
66// Type signature of an entrypoint implementation class (Durable Object or stateless service).
67using ExecutionContextOrState =
68 kj::OneOf<jsg::Ref<api::ExecutionContext>, jsg::Ref<api::DurableObjectState>>;
69using EntrypointClass =
70 jsg::Constructor<api::ExportedHandler(ExecutionContextOrState ctx, jsg::Value env)>;
71 
72// The type of a top-level export -- either a simple handler or a class.
73using NamedExport = kj::OneOf<EntrypointClass, api::ExportedHandler>;
74 
75struct EntrypointClasses {
76 // Class constructor for WorkerEntrypoint.
77 jsg::JsObject workerEntrypoint;
78 
79 // Class constructor for DurableObject (aka api::DurableObjectBase).
80 jsg::JsObject durableObject;
81 
82 // Class constructor for WorkflowEntrypoint
83 jsg::JsObject workflowEntrypoint;
84};
85 
86// An instance of a Worker.
87//
88// Typically each worker script is loaded into a single Worker instance which is reused by
89// multiple requests. The Worker can only be used by one thread at a time, so multiple requests
90// for the same worker can block each other. JavaScript code is asynchronous, though, so any such
91// blocking should be brief.
92//
93// Note: This class should be referred to as "Worker instance" in cases where the bare word
94// "Worker" is ambiguous. I considered naming the class WorkerInstance, but it feels redundant
95// for a class name to end in "Instance". ("I have an instance of WorkerInstance...")
96class Worker: public kj::AtomicRefcounted {
97 public:
98 using VersionInfo = Worker_VersionInfo;
99 class Script;
100 class Isolate;
101 class Api;
102 
103 class ValidationErrorReporter {
104 public:
105 virtual void addError(kj::String error) = 0;
106 
107 // Report that the Worker implements a stateless entrypoint (e.g. WorkerEntrypoint or plain
108 // object export) with the given export name and methods.
109 virtual void addEntrypoint(
110 kj::Maybe<kj::StringPtr> exportName, kj::Array<kj::String> methods) = 0;
111 
112 // Report that the Worker exports a Durable Object class with the given name.
113 virtual void addActorClass(kj::StringPtr exportName) = 0;
114 
115 // Report that the Worker exports a Workflow class with the given name.
116 virtual void addWorkflowClass(kj::StringPtr exportName, kj::Array<kj::String> methods) = 0;
117 };
118 
119 class LockType;
120 
121 enum class ConsoleMode {
122 // Only send `console.log`s to the inspector. Default, production behavior.
123 INSPECTOR_ONLY,
124 // Send `console.log`s to the inspector and stdout/err. Behavior running `workerd` locally.
125 STDOUT,
126 };
127 
128 struct LoggingOptions {
129 ConsoleMode consoleMode = Worker::ConsoleMode::INSPECTOR_ONLY;
130 StructuredLogging structuredLogging = StructuredLogging::NO;
131 ProcessStdioPrefixed processStdioPrefixed = ProcessStdioPrefixed::YES;
132 kj::ConstString stdoutPrefix = "stdout:"_kjc;
133 kj::ConstString stderrPrefix = "stderr:"_kjc;
134 
135 LoggingOptions() = default;
136 LoggingOptions(LoggingOptions&&) = default;
137 LoggingOptions& operator=(LoggingOptions&&) = default;
138 
139 explicit LoggingOptions(ConsoleMode mode): consoleMode(mode) {}
140 
141 LoggingOptions(const LoggingOptions& other)
142 : consoleMode(other.consoleMode),
143 structuredLogging(other.structuredLogging),
144 processStdioPrefixed(other.processStdioPrefixed),
145 stdoutPrefix(other.stdoutPrefix.clone()),
146 stderrPrefix(other.stderrPrefix.clone()) {}
147 
148 LoggingOptions& operator=(const LoggingOptions& other) {
149 consoleMode = other.consoleMode;
150 structuredLogging = other.structuredLogging;
151 processStdioPrefixed = other.processStdioPrefixed;
152 stdoutPrefix = other.stdoutPrefix.clone();
153 stderrPrefix = other.stderrPrefix.clone();
154 return *this;
155 }
156 };
157 
158 explicit Worker(kj::Own<const Script> script,
159 kj::Own<WorkerObserver> metrics,
160 kj::FunctionParam<void(jsg::Lock& lock,
161 const Api& api,
162 v8::Local<v8::Object> target,
163 v8::Local<v8::Object> ctxExports)> compileBindings,
164 IsolateObserver::StartType startType,
165 SpanParent parentSpan,
166 LockType lockType,
167 kj::Maybe<ValidationErrorReporter&> errorReporter = kj::none,
168 kj::Maybe<kj::Duration&> startupTime = kj::none);
169 // `compileBindings()` is a callback that constructs all of the bindings and adds them as
170 // properties to `target`. It also compiles the `ctx.exports` object and writes it to
171 // `ctxExports`. Note that it is permissible for this callback to save a handle to `ctxExports`
172 // and fill it in later if needed, as long as it is filled in before any requests are started.
173 
174 ~Worker() noexcept(false);
175 KJ_DISALLOW_COPY_AND_MOVE(Worker);
176 
177 inline const Script& getScript() const {
178 return *script;
179 }
180 
181 inline const Isolate& getIsolate() const;
182 
183 inline const WorkerObserver& getMetrics() const {
184 return *metrics;
185 }
186 
187 class Lock;
188 
189 inline auto runInLockScope(LockType lockType, auto func) const;
190 
191 class AsyncLock;
192 
193 // Places this thread into the queue of threads which are interested in locking this isolate,
194 // and returns when it is this thread's turn. The thread must still obtain a `Worker::Lock`, but
195 // by obtaining an `AsyncLock` first, the thread ensures that it is not fighting over the lock
196 // with many other threads, and all interested threads get their fair turn.
197 kj::Promise<AsyncLock> takeAsyncLockWithoutRequest(SpanParent parentSpan) const;
198 
199 // Places this thread into the queue of threads which are interested in locking this isolate,
200 // and returns when it is this thread's turn. The thread must still obtain a `Worker::Lock`, but
201 // by obtaining an `AsyncLock` first, the thread ensures that it is not fighting over the lock
202 // with many other threads, and all interested threads get their fair turn.
203 //
204 // The version accepting a `request` metrics object accumulates lock timing data and reports the
205 // data via `request`'s trace span.
206 kj::Promise<AsyncLock> takeAsyncLock(RequestObserver& request) const;
207 
208 class Actor;
209 
210 // Like takeAsyncLock(), but also takes care of actor cache time-based eviction and backpressure.
211 kj::Promise<AsyncLock> takeAsyncLockWhenActorCacheReady(
212 kj::Date now, Actor& actor, RequestObserver& request) const;
213 
214 static void setupContext(
215 jsg::Lock& lock, v8::Local<v8::Context> context, const LoggingOptions& loggingOptions);
216 
217 private:
218 kj::Own<const Script> script;
219 
220 kj::Own<WorkerObserver> metrics;
221 
222 // metrics needs to be first to be destroyed last to correctly capture destruction timing.
223 // it needs script to report destruction time, so it comes right after that.
224 TeardownFinishedGuard<WorkerObserver&> teardownGuard{*metrics};
225 
226 struct Impl;
227 kj::Own<Impl> impl;
228 
229 struct ActorClassInfo {
230 EntrypointClass cls;
231 bool missingSuperclass;
232 };
233 
234 class InspectorClient;
235 class AsyncWaiter;
236 friend constexpr bool _kj_internal_isPolymorphic(AsyncWaiter*);
237 
238 static void handleLog(jsg::Lock& js,
239 const LoggingOptions& loggingOptions,
240 LogLevel level,
241 const v8::Global<v8::Function>& original,
242 const v8::FunctionCallbackInfo<v8::Value>& info);
243 
244 void processEntrypointClass(jsg::Lock& js,
245 EntrypointClass cls,
246 EntrypointClasses entrypointClasses,
247 kj::String handlerName);
248};
249 
250// A compiled script within an Isolate, but which hasn't been instantiated into a particular
251// context (Worker).
252class Worker::Script: public kj::AtomicRefcounted {
253 public:
254 ~Script() noexcept(false);
255 KJ_DISALLOW_COPY_AND_MOVE(Script);
256 
257 inline kj::StringPtr getId() const {
258 return id;
259 }
260 inline const Isolate& getIsolate() const {
261 return *isolate;
262 }
263 inline bool isModular() const {
264 return modular;
265 }
266 inline bool isPython() const {
267 return python;
268 }
269 inline kj::Maybe<kj::Arc<DynamicEnvBuilder>> getDynamicEnvBuilder() const {
270 return mapAddRef(dynamicEnvBuilder);
271 }
272 
273 void installVirtualFileSystemOnContext(v8::Local<v8::Context> context) const;
274 
275 const capnp::SchemaLoader& getSchemaLoader() const;
276 
277 struct CompiledGlobal {
278 jsg::V8Ref<v8::String> name;
279 jsg::V8Ref<v8::Value> value;
280 };
281 
282 // Historically these types were declared here, but then they were moved to `WorkerSource`. We
283 // maintain aliases here for backwards compatibility.
284 // TODO(cleanup): Update all the references, then remove these.
285 using EsModule = WorkerSource::EsModule;
286 using CommonJsModule = WorkerSource::CommonJsModule;
287 using TextModule = WorkerSource::TextModule;
288 using DataModule = WorkerSource::DataModule;
289 using WasmModule = WorkerSource::WasmModule;
290 using JsonModule = WorkerSource::JsonModule;
291 using PythonModule = WorkerSource::PythonModule;
292 using PythonRequirement = WorkerSource::PythonRequirement;
293 using CapnpModule = WorkerSource::CapnpModule;
294 using ModuleContent = WorkerSource::ModuleContent;
295 using Module = WorkerSource::Module;
296 using ScriptSource = WorkerSource::ScriptSource;
297 using ModulesSource = WorkerSource::ModulesSource;
298 using Source = WorkerSource;
299 
300 private:
301 kj::Own<const Isolate> isolate;
302 kj::String id;
303 bool modular;
304 bool python;
305 
306 struct Impl;
307 kj::Own<Impl> impl;
308 
309 kj::Maybe<kj::Arc<DynamicEnvBuilder>> dynamicEnvBuilder;
310 
311 friend class Worker;
312 
313 public: // pretend this is private (needs to be public because allocated through template)
314 explicit Script(kj::Own<const Isolate> isolate,
315 kj::StringPtr id,
316 const Source& source,
317 IsolateObserver::StartType startType,
318 bool logNewScript,
319 kj::Maybe<ValidationErrorReporter&> errorReporter,
320 kj::Maybe<kj::Own<api::pyodide::ArtifactBundler_State>> artifacts,
321 SpanParent parentSpan,
322 kj::Own<workerd::VirtualFileSystem> vfs,
323 kj::Maybe<kj::Arc<workerd::jsg::modules::ModuleRegistry>> maybeNewModuleRegistry);
324};
325 
326// Multiple zones may share the same script. We would like to compile each script only once,
327// yet still provide strong separation between zones. To that end, each Script gets a V8
328// Isolate, while each Zone sharing that script gets a JavaScript context (global object).
329//
330// Note that this means that multiple workers sharing the same script cannot execute
331// concurrently. Worker::Lock takes care of this.
332//
333// An Isolate maintains weak maps of Workers and Scripts loaded within it.
334//
335// An Isolate is persisted by strong references given to each `Worker::Script` returned from
336// `newScript()`. At various points, other strong references are made, but these are generally
337// ephemeral. So when the last script is destructed, the isolate can be expected to also be
338// destructed soon.
339class Worker::Isolate: public kj::AtomicRefcounted {
340 public:
341 // Determines whether a devtools inspector client can be attached.
342 enum class InspectorPolicy {
343 DISALLOW,
344 ALLOW_UNTRUSTED,
345 ALLOW_FULLY_TRUSTED,
346 };
347 
348 // Creates an isolate with the given ID. The ID only matters for metrics-reporting purposes.
349 // Usually it matches the script ID. An exception is preview isolates: there, each preview
350 // session has one isolate which may load many iterations of the script (this allows the
351 // inspector session to stay open across them).
352 // The Isolate object owns the Api object and outlives it in order to report teardown timing.
353 // The Api object is created before the Isolate object and does not strictly require
354 // request-specific information.
355 explicit Isolate(kj::Own<Api> api,
356 kj::Own<IsolateObserver> metrics,
357 kj::StringPtr id,
358 kj::Own<IsolateLimitEnforcer> limitEnforcer,
359 InspectorPolicy inspectorPolicy,
360 LoggingOptions loggingOptions = {});
361 
362 ~Isolate() noexcept(false);
363 KJ_DISALLOW_COPY_AND_MOVE(Isolate);
364 
365 // Get the current Worker::Isolate from the current jsg::Lock
366 static const Isolate& from(jsg::Lock& js);
367 
368 // This callback gets executed when the CPU limiter is nearly out of time. It has to be signal
369 // safe since we call it in a signal handler.
370 //
371 // We give a reference to the callback to the limit enforcer, so it has to outlive the limit
372 // enforcer. The Isolate outlives the limit enforcer. If this function is called a second time, we
373 // throw to avoid invalidating references.
374 void setCpuLimitNearlyExceededCallback(kj::Function<void(void)> cb) const;
375 // Returns a reference to cpuLimitNearlyExceededCallback. Can't outlive the Isolate.
376 kj::Maybe<kj::Function<void(void)>> getCpuLimitNearlyExceededCallback() const;
377 
378 // Registers a WASM module's linear memory and offsets for receiving the "shut down" signal.
379 // At least one of signalOffset or terminatedOffset must be provided. The instance handle is
380 // used to create a weak reference for GC-based cleanup. See
381 // TrackedWasmInstanceList::registerSignal().
382 void registerTrackedWasmInstance(jsg::Lock& js,
383 v8::Local<v8::Object> instance,
384 kj::Array<kj::byte> memory,
385 kj::Maybe<uint32_t> signalOffset,
386 kj::Maybe<uint32_t> terminatedOffset) const;
387 
388 inline IsolateObserver& getMetrics() {
389 return *metrics;
390 }
391 
392 inline const IsolateObserver& getMetrics() const {
393 return *metrics;
394 }
395 
396 inline kj::StringPtr getId() const {
397 return id;
398 }
399 
400 // Parses the given code to create a new script object and returns it.
401 //
402 // Note that the `source` is fully consumed before this method returns, so the underlying buffers
403 // it points into can be freed immediately after the call.
404 kj::Own<const Worker::Script> newScript(kj::StringPtr id,
405 const Script::Source& source,
406 IsolateObserver::StartType startType,
407 SpanParent parentSpan,
408 kj::Own<workerd::VirtualFileSystem> vfs,
409 bool logNewScript = false,
410 kj::Maybe<ValidationErrorReporter&> errorReporter = kj::none,
411 kj::Maybe<kj::Own<api::pyodide::ArtifactBundler_State>> artifacts = kj::none,
412 kj::Maybe<kj::Arc<workerd::jsg::modules::ModuleRegistry>> maybeNewModuleRegistry =
413 kj::none) const;
414 
415 inline IsolateLimitEnforcer& getLimitEnforcer() {
416 return *limitEnforcer;
417 }
418 
419 inline const IsolateLimitEnforcer& getLimitEnforcer() const {
420 return *limitEnforcer;
421 }
422 
423 inline Api& getApi() {
424 return *api;
425 }
426 
427 inline const Api& getApi() const {
428 return *api;
429 }
430 
431 // Returns the number of threads currently blocked trying to lock this isolate's mutex (using
432 // takeAsyncLock()).
433 uint getCurrentLoad() const;
434 
435 // Returns a count that is incremented upon every successful lock.
436 uint getLockSuccessCount() const;
437 
438 // Accepts a connection to the V8 inspector and handles requests until the client disconnects.
439 // Also adds a special JSON value to the header identified by `controlHeaderId`, for compatibility
440 // with internal Cloudflare systems.
441 //
442 // This overload will dispatch all inspector messages on the _calling thread's_ `kj::Executor`.
443 // When linked against vanilla V8, this means that CPU profiling will only profile JavaScript
444 // running on the _calling thread_, which will most likely only be inspector console commands, and
445 // is not typically desired.
446 //
447 // For the above reason , this overload is currently only suitable for use by the internal Workers
448 // Runtime codebase, which patches V8 to profile whichever thread currently holds the `v8::Locker`
449 // for this Isolate.
450 kj::Promise<void> attachInspector(kj::Timer& timer,
451 kj::Duration timerOffset,
452 kj::HttpService::Response& response,
453 const kj::HttpHeaderTable& headerTable,
454 kj::HttpHeaderId controlHeaderId) const;
455 
456 // Accepts a connection to the V8 inspector and handles requests until the client disconnects.
457 //
458 // This overload will dispatch all inspector messages on the `kj::Executor` passed in via
459 // `isolateThreadExecutor`. For CPU profiling to work as expected, this `kj::Executor` must be
460 // associated with the same thread which executes the Worker's JavaScript.
461 kj::Promise<void> attachInspector(kj::Own<const kj::Executor> isolateThreadExecutor,
462 kj::Timer& timer,
463 kj::Duration timerOffset,
464 kj::WebSocket& webSocket) const;
465 
466 // Log a warning to the inspector if attached, and log an INFO severity message.
467 void logWarning(kj::StringPtr description, Worker::Lock& lock);
468 
469 // logWarningOnce() only logs the warning if it has not already been logged for this
470 // worker instance.
471 void logWarningOnce(kj::StringPtr description, Worker::Lock& lock);
472 
473 // Log an ERROR severity message, if it has not already been logged for this worker instance.
474 void logErrorOnce(kj::StringPtr description);
475 
476 // Wrap an HttpClient to report subrequests to inspector.
477 kj::Own<WorkerInterface> wrapSubrequestClient(kj::Own<WorkerInterface> client,
478 kj::HttpHeaderId contentEncodingHeaderId,
479 RequestObserver& requestMetrics) const;
480 
481 inline kj::Maybe<kj::StringPtr> getFeatureFlagsForFl() const {
482 return featureFlagsForFl;
483 }
484 
485 // Called after each completed request. Does not require a lock.
486 void completedRequest() const;
487 
488 // See Worker::takeAsyncLock().
489 kj::Promise<AsyncLock> takeAsyncLockWithoutRequest(SpanParent parentSpan) const;
490 
491 // See Worker::takeAsyncLock().
492 kj::Promise<AsyncLock> takeAsyncLock(RequestObserver&) const;
493 
494 bool isInspectorEnabled() const;
495 
496 // Get the process stdio prefixed setting from logging options
497 inline kj::StringPtr getStdoutPrefix() const {
498 return loggingOptions.stdoutPrefix;
499 }
500 
501 inline kj::StringPtr getStderrPrefix() const {
502 return loggingOptions.stderrPrefix;
503 }
504 
505 // Represents a weak reference back to the isolate that code within the isolate can use as an
506 // indirect pointer when they want to be able to race destruction safely. A caller wishing to
507 // use a weak reference to the isolate should acquire a strong reference to weakIsolateRef.
508 // That will ensure it's always safe to invoke `tryAddStrongRef` to try to obtain a strong
509 // reference of the underlying isolate. This is because the Isolate's destructor will explicitly
510 // clear the underlying pointer that would be dereferenced by `tryAddStrongRef`. This means that
511 // after the refcount reaches 0, `tryAddStrongRef` is always still safe to invoke even if the
512 // underlying Isolate memory has been deallocated (provided ownership of the weak isolate
513 // reference is retained).
514 using WeakIsolateRef = AtomicWeakRef<Isolate>;
515 
516 kj::Own<const WeakIsolateRef> getWeakRef() const;
517 
518 // Get a UUID for this isolate.
519 kj::StringPtr getUuid() const;
520 
521 private:
522 kj::Promise<AsyncLock> takeAsyncLockImpl(
523 kj::Maybe<kj::Own<IsolateObserver::LockTiming>> lockTiming) const;
524 
525 kj::Own<IsolateObserver> metrics;
526 // NOTE: destruction order is important here. The teardown guard should be destroyed after the
527 // `api` since API destruction may perform some aspects of isolate teardown.
528 TeardownFinishedGuard<IsolateObserver&> teardownGuard{*metrics};
529 
530 kj::String id;
531 kj::Own<IsolateLimitEnforcer> limitEnforcer;
532 kj::MutexGuarded<kj::Maybe<kj::Function<void(void)>>> cpuLimitNearlyExceededCallback;
533 kj::Own<Api> api;
534 LoggingOptions loggingOptions;
535 
536 // If non-null, a serialized JSON object with a single "flags" property, which is a list of
537 // compatibility enable-flags that are relevant to FL.
538 kj::Maybe<kj::String> featureFlagsForFl;
539 
540 struct Impl;
541 kj::Own<Impl> impl;
542 
543 // This is a weak reference that can be used to safely (in a multi-threaded context) try to
544 // acquire a strong reference to the isolate. To do that add a strong reference to the
545 // weakIsolateRef while it's safe and then call tryAddStrongRef which will return a strong
546 // reference if the object isn't being destroyed (it's safe to call this even if the destructor
547 // has already run).
548 kj::Own<const WeakIsolateRef> weakIsolateRef;
549 
550 class InspectorChannelImpl;
551 kj::Maybe<InspectorChannelImpl&> currentInspectorSession;
552 
553 struct AsyncWaiterList {
554 kj::Maybe<AsyncWaiter&> head = kj::none;
555 kj::Maybe<AsyncWaiter&>* tail = &head;
556 
557 ~AsyncWaiterList() noexcept;
558 };
559 
560 // Mutex-guarded linked list of threads waiting for an async lock on this worker. The lock
561 // protects the `AsyncWaiterList` as well as the next/prev pointers in each `AsyncWaiter` that
562 // is currently in the list.
563 kj::MutexGuarded<AsyncWaiterList> asyncWaiters;
564 // TODO(perf): Use a lock-free list? Tricky to get right. `asyncWaiters` should only be locked
565 // briefly so there's probably not that much to gain.
566 
567 friend class Worker::AsyncLock;
568 
569 void disconnectInspector();
570 
571 // Log a message as if with console.{log,warn,error,etc}. `type` must be one of the cdp::LogType
572 // enum, which unfortunately we cannot forward-declare, ugh.
573 void logMessage(jsg::Lock& js, uint16_t type, kj::StringPtr description);
574 
575 class SubrequestClient;
576 class ResponseStreamWrapper;
577 class LimitedBodyWrapper;
578 
579 size_t nextRequestId = 0;
580 kj::Own<jsg::AsyncContextFrame::StorageKey> traceAsyncContextKey;
581 kj::Own<jsg::AsyncContextFrame::StorageKey> userTraceAsyncContextKey;
582 
583 friend class Worker;
584};
585 
586// The "API isolate" is a wrapper around JSG which determines which APIs are available. This is
587// an abstract interface which can be customized to make the runtime support a different set of
588// APIs. All JSG wrapping/unwrapping is encapsulated within this.
589//
590// In contrast, the rest of the classes in `worker.h` are concerned more with lifecycle
591// management.
592class Worker::Api {
593 public:
594 // Get the current `Api` or throw if we're not currently executing JavaScript.
595 static const Api& current();
596 // TODO(cleanup): This is a hack thrown in quickly because IoContext::current() doesn't work in
597 // the global scope (when no request is running). We need a better design here.
598 
599 // Like `current()`, but returns `kj::none` if there is no current Api instance.
600 static kj::Maybe<const Api&> tryCurrent();
601 
602 // Take a lock on the isolate.
603 virtual kj::Own<jsg::Lock> lock(jsg::V8StackScope& stackScope) const = 0;
604 // TODO(cleanup): Change all locking to a synchronous callback style rather than RAII style, so
605 // that this doesn't have to allocate and so it's not possible to hold a lock while returning
606 // to the event loop.
607 
608 // Get the FeatureFlags this isolate is configured with. Returns a Reader that is owned by the
609 // Api.
610 virtual CompatibilityFlags::Reader getFeatureFlags() const = 0;
611 
612 struct NewContextOptions {
613 // If the worker is using the new module registry system, this is the registry to
614 // install on the newly created context. If null, the old system is assumed.
615 kj::Maybe<const workerd::jsg::modules::ModuleRegistry&> newModuleRegistry;
616 kj::Maybe<const capnp::SchemaLoader&> schemaLoader;
617 };
618 
619 // Create the context (global scope) object.
620 virtual jsg::JsContext<api::ServiceWorkerGlobalScope> newContext(
621 jsg::Lock& lock, NewContextOptions options = {}) const = 0;
622 
623 virtual void compileModules(jsg::Lock& lock,
624 const Script::ModulesSource& source,
625 const Worker::Isolate& isolate,
626 kj::Maybe<kj::Own<api::pyodide::ArtifactBundler_State>> artifacts,
627 SpanParent parentSpan) const = 0;
628 
629 virtual kj::Array<Worker::Script::CompiledGlobal> compileServiceWorkerGlobals(jsg::Lock& lock,
630 const Script::ScriptSource& source,
631 const Worker::Isolate& isolate) const = 0;
632 
633 // Given a module's export namespace, return all the top-level exports.
634 virtual jsg::Dict<NamedExport> unwrapExports(
635 jsg::Lock& lock, v8::Local<v8::Value> moduleNamespace) const = 0;
636 
637 virtual NamedExport unwrapExport(jsg::Lock& lock, v8::Local<v8::Value> exportVal) const = 0;
638 
639 // Get the constructors for classes from which entrypoint classes may inherit.
640 //
641 // This can be used to check which class a particular entrypoint inherits from, by following
642 // the prototype chain from the entrypoint class's constructor.
643 virtual EntrypointClasses getEntrypointClasses(jsg::Lock& lock) const = 0;
644 
645 // Convenience struct for accessing typical Error properties.
646 struct ErrorInterface {
647 jsg::Optional<kj::String> name;
648 jsg::Optional<kj::String> message;
649 jsg::Optional<kj::String> stack;
650 JSG_STRUCT(name, message, stack);
651 };
652 virtual const jsg::TypeHandler<ErrorInterface>& getErrorInterfaceTypeHandler(
653 jsg::Lock& lock) const = 0;
654 virtual const jsg::TypeHandler<api::QueueExportedHandler>& getQueueTypeHandler(
655 jsg::Lock& lock) const = 0;
656 
657 // Look up crypto algorithms by case-insensitive name. This can be used to extend the set of
658 // WebCrypto algorithms supported.
659 virtual kj::Maybe<const api::CryptoAlgorithm&> getCryptoAlgorithm(kj::StringPtr name) const {
660 return kj::none;
661 }
662 
663 // Apply JSG wrapping to the given ExecutionContext. This is needed in particular by the RPC
664 // server-side implementation, when invoking a top-level RPC method that takes env and ctx as
665 // params.
666 virtual jsg::JsObject wrapExecutionContext(
667 jsg::Lock& lock, jsg::Ref<api::ExecutionContext> ref) const = 0;
668 
669 // Hook for the embedding application to provide a CacheContext for the ctx.cache property.
670 // The default implementation returns kj::none (undefined).
671 virtual jsg::Optional<jsg::Ref<api::CacheContext>> getCtxCacheProperty(jsg::Lock& js) const;
672 
673 virtual const jsg::IsolateObserver& getObserver() const = 0;
674 virtual void setIsolateObserver(IsolateObserver&) = 0;
675 
676 // Set the module fallback service callback, if any.
677 using ModuleFallbackCallback = kj::Maybe<kj::OneOf<kj::String, jsg::ModuleRegistry::ModuleInfo>>(
678 jsg::Lock& js,
679 kj::StringPtr,
680 kj::Maybe<kj::String>,
681 jsg::CompilationObserver&,
682 jsg::ModuleRegistry::ResolveMethod,
683 kj::Maybe<kj::StringPtr>);
684 virtual void setModuleFallbackCallback(kj::Function<ModuleFallbackCallback>&& callback) const {
685 // By default does nothing.
686 }
687};
688 
689// A Worker may bounce between threads as it handles multiple requests, but can only actually
690// execute on one thread at a time. Each thread must therefore lock the Worker while executing
691// code.
692//
693// A Worker::Lock MUST be allocated on the stack.
694class Worker::Lock {
695 public:
696 // Worker locks should normally be taken asynchronously. The TakeSynchronously type can be used
697 // when a synchronous lock is unavoidable. The purpose of this type is to make it easy to find
698 // all the places where we take synchronous locks.
699 class TakeSynchronously {
700 public:
701 // We don't provide a default constructor so that call sites need to think about whether they
702 // have a Request& available to pass in.
703 explicit TakeSynchronously(kj::Maybe<RequestObserver&> request);
704 
705 kj::Maybe<RequestObserver&> getRequest();
706 
707 private:
708 // Non-null if this lock is being taken on behalf of a request.
709 RequestObserver* request = nullptr;
710 // HACK: The OneOf<TakeSynchronously, ...> in Worker::LockType doesn't like that
711 // Maybe<RequestObserver&> forces us to have a mutable copy constructor. I couldn't figure
712 // out how to work around it, so here we are with a raw pointer. :/
713 };
714 
715 KJ_DISALLOW_COPY_AND_MOVE(Lock);
716 KJ_DISALLOW_AS_COROUTINE_PARAM;
717 ~Lock() noexcept(false);
718 
719 void requireNoPermanentException();
720 
721 Worker& getWorker() {
722 return worker;
723 }
724 
725 operator jsg::Lock&();
726 
727 v8::Isolate* getIsolate();
728 v8::Local<v8::Context> getContext();
729 
730 bool isInspectorEnabled();
731 void logWarning(kj::StringPtr description);
732 void logWarningOnce(kj::StringPtr description);
733 
734 void logErrorOnce(kj::StringPtr description);
735 
736 // Logs an exception to the debug console or trace, if active.
737 void logUncaughtException(kj::StringPtr description);
738 
739 // Logs an exception to the debug console or trace, if active.
740 //
741 // If the caller already has a copy of the exception stack, it can pass this in as an
742 // optimization. This value will be passed along to the trace handler, if there is one, rather
743 // than querying the property from the exception itself. This is also useful in the case that
744 // the exception itself is not the original and the stack is missing.
745 void logUncaughtException(UncaughtExceptionSource source,
746 const jsg::JsValue& exception,
747 const jsg::JsMessage& message = jsg::JsMessage());
748 
749 // Version that takes a kj::Exception. If it has a serialized JS error attached as a detail, that
750 // error may be extracted and used.
751 void logUncaughtException(UncaughtExceptionSource source, kj::Exception&& exception);
752 
753 void reportPromiseRejectEvent(v8::PromiseRejectMessage& message);
754 
755 // Checks for problems with the registered event handlers (such as that there are none) and
756 // reports them to the error reporter.
757 void validateHandlers(ValidationErrorReporter& errorReporter);
758 
759 // Get the ExportedHandler exported under the given name. `entrypointName` may be null to get the
760 // default handler. Returns null if this is not a modules-syntax worker (but `entrypointName`
761 // must be null in that case).
762 //
763 // `versionInfo` is used to populate `ctx.version` when enabled.
764 // `props` is the value to place in `ctx.props`.
765 //
766 // If running in an actor, the name and props are ignored and the entrypoint originally used to
767 // construct the actor is returned.
768 //
769 // `isDynamicDispatch` indicates the entrypoint name was supplied at request time (e.g. by the
770 // Workflows engine via dynamic dispatch) rather than baked into the pipeline at config time. When
771 // true, a missing entrypoint is surfaced as a JSG TypeError to the caller rather than being
772 // logged as an internal error, since the mismatch is attributable to user configuration.
773 kj::Maybe<kj::Own<api::ExportedHandler>> getExportedHandler(
774 kj::Maybe<kj::StringPtr> entrypointName,
775 kj::Maybe<VersionInfo> versionInfo,
776 Frankenvalue props,
777 kj::Maybe<Worker::Actor&> actor,
778 bool isDynamicDispatch = false);
779 
780 // Get the C++ object representing the global scope.
781 api::ServiceWorkerGlobalScope& getGlobalScope();
782 
783 // Get the timeout ID generator from this worker's ServiceWorkerGlobalScope.
784 TimeoutId::Generator& getTimeoutIdGenerator();
785 
786 // Get the opaque storage key to use for recording trace information in async contexts.
787 jsg::AsyncContextFrame::StorageKey& getTraceAsyncContextKey();
788 
789 // Get the opaque storage key to use for recording user trace information in async contexts.
790 jsg::AsyncContextFrame::StorageKey& getUserTraceAsyncContextKey();
791 
792 private:
793 explicit Lock(const Worker& worker, LockType lockType, jsg::V8StackScope&);
794 struct Impl;
795 
796 Worker& worker;
797 kj::Own<Impl> impl;
798 
799 friend class Worker;
800};
801 
802// Can be initialized either from an `AsyncLock` or a `TakeSynchronously`, to indicate whether an
803// async lock is held and help us grep for places in the code that do not support async locks.
804class Worker::LockType {
805 public:
806 LockType(Lock::TakeSynchronously origin): origin(origin) {}
807 LockType(AsyncLock& origin): origin(&origin) {}
808 
809 private:
810 kj::OneOf<Lock::TakeSynchronously, AsyncLock*> origin;
811 friend class Worker::Isolate;
812};
813 
814// The func must be a callback with the signature: T (jsg::Lock&), where T is any type.
815auto Worker::runInLockScope(LockType lockType, auto func) const {
816 return jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) -> auto {
817 Worker::Lock lock(*this, lockType, stackScope);
818 return func(lock);
819 });
820}
821 
822// Represents the thread's ownership of an isolate's asynchronous lock. Call `takeAsyncLock()`
823// on a `Worker` or `Worker::Isolate` to obtain this. Pass it to the constructor of
824// `Worker::Lock` (as the `lockType`) in order to indicate that the calling thread has taken
825// the async lock first.
826//
827// You must never store an `AsyncLock` long-term. Use it in a continuation and then discard it.
828// To put it another way: An `AsyncLock` instance must never outlive an `evalLast()`.
829class Worker::AsyncLock {
830 public:
831 // Waits until the thread has no async locks, is not waiting on any locks, and has finished all
832 // pending events (a la `kj::evalLast()`).
833 static kj::Promise<void> whenThreadIdle();
834 
835 private:
836 kj::Own<AsyncWaiter> waiter;
837 kj::Maybe<kj::Own<IsolateObserver::LockTiming>> lockTiming;
838 
839 AsyncLock(kj::Own<AsyncWaiter> waiter, kj::Maybe<kj::Own<IsolateObserver::LockTiming>> lockTiming)
840 : waiter(kj::mv(waiter)),
841 lockTiming(kj::mv(lockTiming)) {}
842 
843 friend class Worker::Isolate;
844 friend class Worker::AsyncWaiter;
845};
846 
847// Represents actor state within a Worker instance. This object tracks the JavaScript heap
848// objects backing `event.actorState`. Multiple `Actor`s can be created within a single `Worker`.
849class Worker::Actor final: public kj::Refcounted {
850 public:
851 // Callback which constructs the `ActorCacheInterface` instance (if any) for the Actor. This
852 // can be used to customize the storage implementation. This will be called synchronously in
853 // the constructor.
854 using MakeActorCacheFunc =
855 kj::Function<kj::Maybe<kj::Own<ActorCacheInterface>>(const ActorCache::SharedLru& sharedLru,
856 OutputGate& outputGate,
857 ActorCache::Hooks& hooks,
858 SqliteObserver& sqliteObserver)>;
859 
860 // Callback which constructs the `DurableObjectStorage` instance for an actor. This can be used
861 // to customize the JavaScript API.
862 using MakeStorageFunc = kj::Function<jsg::Ref<api::DurableObjectStorage>(
863 jsg::Lock& js, const Api& api, ActorCacheInterface& actorCache)>;
864 // TODO(cleanup): Can we refactor the (internal-codebase) user of this so that it doesn't need
865 // to customize the JS API but only the underlying ActorCacheInterface?
866 
867 using Id = kj::OneOf<kj::Own<ActorIdFactory::ActorId>, kj::String>;
868 static bool idsEqual(const Id& a, const Id& b);
869 
870 // Class that allows sending requests to this actor, recreating it as needed. It is safe to hold
871 // onto this for longer than a Worker::Actor is alive.
872 class Loopback {
873 public:
874 // Send a request to this actor, potentially re-creating it if it is not currently active.
875 // The returned kj::Own<WorkerInterface> may be held longer than Loopback, and is assumed
876 // to keep the Worker::Actor alive as well.
877 virtual kj::Own<WorkerInterface> getWorker(IoChannelFactory::SubrequestMetadata metadata) = 0;
878 
879 virtual kj::Own<Loopback> addRef() = 0;
880 };
881 
882 // The HibernationManager class manages HibernatableWebSockets created by an actor.
883 // The manager handles accepting new WebSockets, retrieving existing WebSockets by tag, and
884 // removing WebSockets from its collection when they disconnect.
885 class HibernationManager: public kj::Refcounted {
886 public:
887 virtual void acceptWebSocket(jsg::Ref<api::WebSocket> ws, kj::ArrayPtr<kj::String> tags) = 0;
888 virtual kj::Vector<jsg::Ref<api::WebSocket>> getWebSockets(
889 jsg::Lock& js, kj::Maybe<kj::StringPtr> tag) = 0;
890 virtual void hibernateWebSockets(Worker::Lock& lock) = 0;
891 virtual void setWebSocketAutoResponse(
892 kj::Maybe<kj::StringPtr> request, kj::Maybe<kj::StringPtr> response) = 0;
893 virtual kj::Maybe<jsg::Ref<api::WebSocketRequestResponsePair>> getWebSocketAutoResponse(
894 jsg::Lock& js) = 0;
895 virtual void setTimerChannel(TimerChannel& timerChannel) = 0;
896 virtual kj::Own<HibernationManager> addRef() = 0;
897 virtual void setEventTimeout(kj::Maybe<uint32_t> timeoutMs) = 0;
898 virtual kj::Maybe<uint32_t> getEventTimeout() = 0;
899 };
900 
901 class FacetManager {
902 public:
903 // Information needed to start a facet.
904 struct StartInfo {
905 // The actor class, from a DurableObjectClass binding.
906 //
907 // WARNING: The object passed here MUST be directly from IoChannelFactory::getActorClass(),
908 // as the FacetManager implementation is allowed to assume it can downcast to whatever
909 // type the IoChannelFactory produces.
910 kj::Own<IoChannelFactory::ActorClassChannel> actorClass;
911 
912 // ctx.id for the child object.
913 Worker::Actor::Id id;
914 };
915 
916 // Returns the nesting depth of this facet. Root = 0, direct child of root = 1, etc.
917 virtual uint getDepth() const = 0;
918 
919 // These methods are C++ equivalents of the JavaScript ctx.facets API.
920 virtual kj::Own<IoChannelFactory::ActorChannel> getFacet(
921 kj::StringPtr name, kj::Function<kj::Promise<StartInfo>()> getStartInfo) = 0;
922 virtual void abortFacet(kj::StringPtr name, kj::Exception reason) = 0;
923 virtual void deleteFacet(kj::StringPtr name) = 0;
924 };
925 
926 // Create a new Actor hosted by this Worker. Note that this Actor object may only be manipulated
927 // from the thread that created it.
928 Actor(const Worker& worker,
929 kj::Maybe<RequestTracker&> tracker,
930 Id actorId,
931 bool hasTransient,
932 MakeActorCacheFunc makeActorCache,
933 kj::Maybe<kj::StringPtr> className,
934 Frankenvalue props,
935 MakeStorageFunc makeStorage,
936 kj::Own<Loopback> loopback,
937 TimerChannel& timerChannel,
938 kj::Own<ActorObserver> metrics,
939 kj::Maybe<kj::Own<HibernationManager>> manager,
940 kj::Maybe<uint16_t> hibernationEventType,
941 kj::Maybe<rpc::Container::Client> container = kj::none,
942 kj::Maybe<FacetManager&> facetManager = kj::none,
943 kj::Maybe<ActorVersion> version = kj::none);
944 
945 ~Actor() noexcept(false);
946 
947 // Call when starting any new request, to ensure that the actor object's constructor has run.
948 //
949 // This is used only for modules-syntax actors (which most are, since that's the only format we
950 // support publicly).
951 void ensureConstructed(IoContext&);
952 
953 // Forces cancellation of all "background work" this actor is executing, i.e. work that is not
954 // happening on behalf of an active request. Note that this is not a part of the dtor because
955 // IoContext objects prolong the lifetime of their Actor.
956 //
957 // `reasonCode` is passed back to the WorkerObserver.
958 void shutdown(uint16_t reasonCode, kj::Maybe<const kj::Exception&> error = kj::none);
959 
960 // Stops new work on behalf of the ActorCache. This does not cancel any ongoing flushes.
961 // TODO(soon) This should probably be folded into shutdown(). We'd need a piece that converts
962 // `error` to `reasonCode` in workerd to do this. There may also be opportunities to streamline
963 // interactions between `onAbort` and `onShutdown` promises.
964 void shutdownActorCache(kj::Maybe<const kj::Exception&> error);
965 
966 // Get a promise that resolves when `shutdown()` has been called.
967 kj::Promise<void> onShutdown();
968 
969 // Get a promise that rejects when this actor becomes broken in some way. See doc comments for
970 // WorkerRuntime.makeActor() in worker.capnp for a discussion of actor brokenness.
971 // Note that this doesn't cover every cause of actor brokenness -- some of them are fulfilled
972 // in worker-set or process-sandbox code, in particular code updates and exceeded memory.
973 // This method can only be called once.
974 kj::Promise<void> onBroken();
975 
976 const Id& getId();
977 Id cloneId();
978 static Id cloneId(Id& id);
979 kj::Maybe<jsg::JsRef<jsg::JsValue>> getTransient(Worker::Lock& lock);
980 kj::Maybe<ActorCacheInterface&> getPersistent();
981 kj::Own<Loopback> getLoopback();
982 
983 // Make the storage object for use in Service Workers syntax. This should not be used for
984 // modules-syntax workers. (Note that Service-Workers-syntax actors are not supported publicly.)
985 kj::Maybe<jsg::Ref<api::DurableObjectStorage>> makeStorageForSwSyntax(Worker::Lock& lock);
986 
987 ActorObserver& getMetrics();
988 
989 InputGate& getInputGate();
990 OutputGate& getOutputGate();
991 
992 // Get the IoContext which should be used for all activity in this Actor. Returns null if
993 // setIoContext() hasn't been called yet.
994 kj::Maybe<IoContext&> getIoContext();
995 
996 // Set the IoContext for this actor. This is called once, when starting the first request
997 // to the actor.
998 void setIoContext(kj::Own<IoContext> context);
999 // TODO(cleanup): Could we make it so the Worker::Actor can create the IoContext directly,
1000 // rather than have WorkerEntrypoint create it on the first request? We'd have to plumb through
1001 // some more information to the place where `Actor` is created, which might be uglier than it's
1002 // worth.
1003 
1004 // Get the `ctx` object for this actor.
1005 jsg::JsObject getCtx(jsg::Lock& js);
1006 
1007 // Get the `env` object for this actor.
1008 jsg::JsValue getEnv(jsg::Lock& js);
1009 
1010 // Get the HibernationManager which should be used for all activity in this Actor. Returns null if
1011 // setHibernationManager() hasn't been called yet.
1012 kj::Maybe<HibernationManager&> getHibernationManager();
1013 
1014 // Set the HibernationManager for this actor. This is called once, on the first call to
1015 // `acceptWebSocket`.
1016 void setHibernationManager(kj::Own<HibernationManager> manager);
1017 
1018 // Gets the event type ID of the hibernation event, which is defined outside of workerd.
1019 // Only needs to be called when allocating a HibernationManager!
1020 kj::Maybe<uint16_t> getHibernationEventType();
1021 
1022 inline const Worker& getWorker() {
1023 return *worker;
1024 }
1025 
1026 void assertCanSetAlarm();
1027 
1028 // If there is a scheduled or running alarm with the given `scheduledTime`, return a promise to
1029 // its result. This allows use to de-dupe multiple requests to a single `IoContext::run()`.
1030 kj::Maybe<kj::Promise<WorkerInterface::AlarmOutcome>> getAlarm(kj::Date scheduledTime);
1031 
1032 // Wait for `Date.now()` to be greater than or equal to `scheduledTime`. If the promise resolves
1033 // to an `AlarmFulfiller`, then the caller is responsible for invoking `fulfill()`, `reject()`, or
1034 // `cancel()`. Otherwise, the scheduled alarm was overridden by another call to `scheduleAlarm()`
1035 // and thus was cancelled. Note that callers likely want to invoke `getAlarm()` first to see if
1036 // there is an existing alarm at `scheduledTime` for which they want to wait (instead of
1037 // cancelling it).
1038 kj::Promise<WorkerInterface::ScheduleAlarmResult> scheduleAlarm(kj::Date scheduledTime);
1039 
1040 kj::Own<Worker::Actor> addRef();
1041 
1042 private:
1043 kj::Promise<WorkerInterface::ScheduleAlarmResult> handleAlarm(kj::Date scheduledTime);
1044 
1045 kj::Own<const Worker> worker;
1046 kj::Maybe<kj::Own<RequestTracker>> tracker;
1047 struct Impl;
1048 kj::Own<Impl> impl;
1049 
1050 kj::Maybe<api::ExportedHandler&> getHandler();
1051 friend class Worker;
1052 
1053 kj::Promise<void> ensureConstructedImpl(IoContext&, ActorClassInfo& info);
1054};
1055 
1056WD_STRONG_BOOL(PopulateVersionInfoMetadata);
1057 
1058// Version information associated with a worker. These are made available through `ctx.version`.
1059// This is also available through the preferred `Worker::VersionInfo` alias. `Worker_VersionInfo`
1060// exists to allow for forward declaration in a couple of niche places.
1061struct Worker_VersionInfo {
1062 kj::String id;
1063 kj::Maybe<kj::String> cohort;
1064 kj::Maybe<kj::String> key;
1065 kj::Maybe<kj::String> versionOverride;
1066 
1067 Worker_VersionInfo clone() const {
1068 return {
1069 .id = kj::str(id),
1070 .cohort = cohort.map([](const kj::String& s) { return kj::str(s); }),
1071 .key = key.map([](const kj::String& s) { return kj::str(s); }),
1072 .versionOverride = versionOverride.map([](const kj::String& s) { return kj::str(s); }),
1073 };
1074 }
1075 
1076 jsg::JsValue toJs(jsg::Lock& js, PopulateVersionInfoMetadata populateVersionInfoMetadata) const {
1077 auto version = js.obj();
1078 if (populateVersionInfoMetadata) {
1079 auto metadata = js.obj();
1080 metadata.set(js, "id"_kj, js.str(id));
1081 version.set(js, "metadata"_kj, metadata);
1082 }
1083 KJ_IF_SOME(someCohort, cohort) {
1084 version.set(js, "cohort"_kj, js.str(someCohort));
1085 }
1086 KJ_IF_SOME(someKey, key) {
1087 version.set(js, "key"_kj, js.str(someKey));
1088 }
1089 KJ_IF_SOME(someVersionOverride, versionOverride) {
1090 version.set(js, "override"_kj, js.str(someVersionOverride));
1091 }
1092 version.recursivelyFreeze(js);
1093 return version;
1094 }
1095};
1096 
1097// =======================================================================================
1098// inline implementation details
1099 
1100inline const Worker::Isolate& Worker::getIsolate() const {
1101 return *script->isolate;
1102}
1103 
1104KJ_DECLARE_NON_POLYMORPHIC(Worker::AsyncWaiter);
1105 
1106// An implementation of Worker::ValidationErrorReporter that collects errors into
1107// a kj::Vector<kj::String>.
1108struct SimpleWorkerErrorReporter final: public Worker::ValidationErrorReporter {
1109 void addError(kj::String error) override {
1110 errors.add(kj::mv(error));
1111 }
1112 void addEntrypoint(kj::Maybe<kj::StringPtr> exportName, kj::Array<kj::String> methods) override {
1113 KJ_UNREACHABLE;
1114 }
1115 void addActorClass(kj::StringPtr exportName) override {
1116 KJ_UNREACHABLE;
1117 }
1118 
1119 void addWorkflowClass(kj::StringPtr exportName, kj::Array<kj::String> methods) override {
1120 KJ_UNREACHABLE;
1121 }
1122 
1123 SimpleWorkerErrorReporter() = default;
1124 KJ_DISALLOW_COPY_AND_MOVE(SimpleWorkerErrorReporter);
1125 kj::Vector<kj::String> errors;
1126};
1127 
1128} // namespace workerd