Skip to content
File

Blob: src/rust/worker/kill_switch.rs

rust115 lines
1// Copyright (c) 2026 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 
5use std::pin::Pin;
6use std::time::SystemTime;
7 
8use cxx::KjError;
9use kj::http::ConnectResponse;
10use kj::http::ConnectSettings;
11use kj::http::HeadersRef;
12use kj::http::Method;
13use kj::http::ServiceResponse;
14use kj::io::AsyncInputStream;
15use kj::io::AsyncIoStream;
16use outcome_capnp::EventOutcome;
17 
18use crate::AlarmResult;
19use crate::CustomEvent;
20use crate::CustomEventResult;
21use crate::Interface;
22use crate::Result;
23use crate::ScheduledResult;
24use crate::exception::SCRIPT_KILLED_DETAIL_ID;
25use crate::ffi::Wrapper;
26 
27#[cxx::bridge(namespace = "workerd::rust::worker")]
28pub mod bridge {
29 extern "Rust" {
30 type Wrapper = crate::ffi::Wrapper;
31 
32 #[expect(
33 clippy::unnecessary_box_returns,
34 reason = "c++ expects heap-allocation"
35 )]
36 fn new_kill_switch_worker() -> Box<Wrapper>;
37 }
38}
39 
40/// Worker implementation that reports Script Killed error for all methods.
41pub struct Worker {}
42 
43impl Worker {
44 fn error(file: &str, line: u32) -> Result<()> {
45 Err(KjError::new(
46 cxx::KjExceptionType::Overloaded,
47 "jsg.Error: This script has been killed.".to_owned(),
48 )
49 .with_details(vec![(SCRIPT_KILLED_DETAIL_ID, vec![])])
50 .with_location(file.to_owned(), line))
51 }
52}
53 
54#[async_trait::async_trait(?Send)]
55impl kj::http::Service for Worker {
56 async fn request<'a>(
57 &'a mut self,
58 _method: Method,
59 _url: &'a [u8],
60 _headers: HeadersRef<'a>,
61 _request_body: Pin<&'a mut AsyncInputStream>,
62 _response: ServiceResponse<'a>,
63 ) -> Result<()> {
64 Self::error(file!(), line!())
65 }
66 
67 async fn connect<'a>(
68 &'a mut self,
69 _host: &'a [u8],
70 _headers: HeadersRef<'a>,
71 _connection: Pin<&'a mut AsyncIoStream>,
72 _response: ConnectResponse<'a>,
73 _settings: ConnectSettings<'a>,
74 ) -> Result<()> {
75 Self::error(file!(), line!())
76 }
77}
78 
79#[async_trait::async_trait(?Send)]
80impl Interface for Worker {
81 async fn run_scheduled(
82 &mut self,
83 _scheduled_time: &SystemTime,
84 _cron: &str,
85 ) -> Result<ScheduledResult> {
86 Ok(ScheduledResult {
87 retry: false,
88 outcome: EventOutcome::KillSwitch,
89 })
90 }
91 
92 async fn run_alarm(
93 &mut self,
94 _scheduled_time: &SystemTime,
95 _retry_count: u32,
96 ) -> Result<AlarmResult> {
97 Ok(AlarmResult {
98 retry: false,
99 retry_counts_against_limit: true,
100 outcome: EventOutcome::KillSwitch,
101 error_description: None,
102 })
103 }
104 
105 async fn custom_event(&mut self, _event: Pin<&mut CustomEvent>) -> Result<CustomEventResult> {
106 Ok(CustomEventResult {
107 outcome: EventOutcome::KillSwitch,
108 })
109 }
110}
111 
112pub fn new_kill_switch_worker() -> Box<Wrapper> {
113 Worker {}.into_ffi()
114}