Skip to main content

fastly/
compute_runtime.rs

1//! Functions for interacting with the runtime of the Compute service.
2//!
3
4use fastly_shared::FastlyStatus;
5use fastly_sys::fastly_compute_runtime::{get_heap_mib, get_vcpu_ms};
6#[cfg(not(target_env = "p1"))]
7use fastly_sys::service0_1_0::fastly::compute as wit;
8use std::sync::OnceLock;
9
10/// Get the amount of vCPU time that has passed since this instance was started,
11/// in milliseconds.
12///
13/// This function returns only time spent running on a vCPU, and does not include
14/// time spent performing any I/O operations. However, it is based on clock time
15/// passing, and so will include time spent executing hostcalls, is heavily
16/// affected by what core of what CPU is running the code, and can even be
17/// influenced by the state of the CPU.
18///
19/// As a result, this function *should not be used in benchmarking across runs*.
20/// It can be used, with caution, to compare the runtime of different operations
21/// within the same session.
22pub fn elapsed_vcpu_ms() -> Result<u64, FastlyStatus> {
23    let mut vcpu_time = 0u64;
24    let vcpu_time_result = unsafe { get_vcpu_ms(&mut vcpu_time) };
25    if vcpu_time_result != FastlyStatus::OK {
26        return Err(vcpu_time_result);
27    }
28    Ok(vcpu_time)
29}
30
31/// Get the current dynamic memory usage of this sandbox, rounded up to the nearest mebibyte (2^20
32/// bytes).
33///
34/// The memory accounted includes the WASM linear memory (i.e. heap memory), as well as some memory
35/// used by the hosting environment; for instance, HTTP bodies that have been read from a TCP
36/// connection, but not read by the WASM program. As such, this function provides only a snapshot
37/// in time: the memory usage can change without any action from the WASM program. It can also
38/// change across runs, as the Compute platform's memory usage changes. Consider the returned value
39/// with these possibilities in mind.
40pub fn heap_memory_snapshot_mib() -> Result<u32, FastlyStatus> {
41    let mut memory_mib = 0u32;
42    let result = unsafe { get_heap_mib(&mut memory_mib) };
43    if result != FastlyStatus::OK {
44        return Err(result);
45    }
46    Ok(memory_mib)
47}
48
49/// The hostname of the Fastly cache server which is executing the current instance, for
50/// example, `cache-jfk1034`.
51///
52/// Equivalent to the "FASTLY_HOSTNAME" environment variable and to [`server.hostname`] in VCL.
53///
54/// [`server.hostname`]: https://www.fastly.com/documentation/reference/vcl/variables/server/server-hostname/
55pub fn hostname() -> &'static str {
56    static HOSTNAME: OnceLock<String> = OnceLock::new();
57
58    #[cfg(target_env = "p1")]
59    {
60        HOSTNAME.get_or_init(|| std::env::var("FASTLY_HOSTNAME").unwrap())
61    }
62
63    #[cfg(not(target_env = "p1"))]
64    {
65        HOSTNAME.get_or_init(wit::compute_runtime::get_hostname)
66    }
67}
68
69/// The three-character identifying code of the [Fastly POP] in which the current instance is
70/// running.
71///
72/// Equivalent to the "FASTLY_POP" environment variable and to [`server.datacenter`] in VCL.
73///
74/// [Fastly POP]: https://www.fastly.com/documentation/guides/concepts/pop/
75/// [`server.datacenter`]: https://www.fastly.com/documentation/reference/vcl/variables/server/server-datacenter/
76pub fn pop() -> &'static str {
77    static POP: OnceLock<String> = OnceLock::new();
78
79    #[cfg(target_env = "p1")]
80    {
81        POP.get_or_init(|| std::env::var("FASTLY_POP").unwrap())
82    }
83
84    #[cfg(not(target_env = "p1"))]
85    {
86        POP.get_or_init(wit::compute_runtime::get_pop)
87    }
88}
89
90/// A code representing the general region of the world in which the [Fastly POP] processing the
91/// current Compute instance resides.
92///
93/// Equivalent to the "FASTLY_REGION" environment variable and to [`server.region`] in VCL, and has
94/// the same possible values.
95///
96/// [`server.region`]: https://www.fastly.com/documentation/reference/vcl/variables/server/server-region/
97/// [Fastly POP]: https://www.fastly.com/documentation/guides/concepts/pop/
98pub fn region() -> &'static str {
99    static REGION: OnceLock<String> = OnceLock::new();
100
101    #[cfg(target_env = "p1")]
102    {
103        REGION.get_or_init(|| std::env::var("FASTLY_REGION").unwrap())
104    }
105
106    #[cfg(not(target_env = "p1"))]
107    {
108        REGION.get_or_init(wit::compute_runtime::get_region)
109    }
110}
111
112/// The current cache identifier for this Fastly service.
113///
114/// Equivalent to the "FASTLY_CACHE_GENERATION" environment variable and to [`req.vcl.generation`]
115/// in VCL.
116///
117/// [`req.vcl.generation`]: https://www.fastly.com/documentation/reference/vcl/variables/miscellaneous/req-vcl-generation/
118pub fn cache_generation() -> u64 {
119    static CACHE_GENERATION: OnceLock<u64> = OnceLock::new();
120
121    #[cfg(target_env = "p1")]
122    {
123        *CACHE_GENERATION.get_or_init(|| {
124            std::env::var("FASTLY_CACHE_GENERATION")
125                .unwrap()
126                .parse()
127                .unwrap()
128        })
129    }
130
131    #[cfg(not(target_env = "p1"))]
132    {
133        *CACHE_GENERATION.get_or_init(wit::compute_runtime::get_cache_generation)
134    }
135}
136
137/// The customer ID of the Fastly customer account to which the currently executing service
138/// belongs.
139///
140/// Equivalent to the "FASTLY_CUSTOMER_ID" environment variable and to [`req.customer_id`] in VCL.
141///
142/// [`req.customer_id`]: https://www.fastly.com/documentation/reference/vcl/variables/miscellaneous/req-customer-id/
143pub fn customer_id() -> &'static str {
144    static CUSTOMER_ID: OnceLock<String> = OnceLock::new();
145
146    #[cfg(target_env = "p1")]
147    {
148        CUSTOMER_ID.get_or_init(|| std::env::var("FASTLY_CUSTOMER_ID").unwrap())
149    }
150
151    #[cfg(not(target_env = "p1"))]
152    {
153        CUSTOMER_ID.get_or_init(wit::compute_runtime::get_customer_id)
154    }
155}
156
157/// Whether the request is running in the service's [staging environment].
158///
159/// `false` for production or `true` for staging.
160///
161/// Equivalent to the "FASTLY_IS_STAGING" environment variable and to [`fastly.is_staging`] in VCL.
162///
163/// [`fastly.is_staging`]: https://www.fastly.com/documentation/reference/vcl/variables/miscellaneous/fastly-is-staging/
164/// [staging environment]: https://docs.fastly.com/products/staging
165pub fn is_staging() -> bool {
166    static IS_STAGING: OnceLock<bool> = OnceLock::new();
167
168    #[cfg(target_env = "p1")]
169    {
170        *IS_STAGING.get_or_init(
171            || match std::env::var("FASTLY_IS_STAGING").unwrap().as_str() {
172                "0" => false,
173                "1" => true,
174                _ => unreachable!(),
175            },
176        )
177    }
178
179    #[cfg(not(target_env = "p1"))]
180    {
181        *IS_STAGING.get_or_init(wit::compute_runtime::get_is_staging)
182    }
183}
184
185/// The identifier for the Fastly service that is processing the current request.
186///
187/// Equivalent to the "FASTLY_SERVICE_ID" environment variable and to [`req.service_id`] in VCL.
188///
189/// [`req.service_id`]: https://www.fastly.com/documentation/reference/vcl/variables/miscellaneous/req-service-id/
190pub fn service_id() -> &'static str {
191    static SERVICE_ID: OnceLock<String> = OnceLock::new();
192
193    #[cfg(target_env = "p1")]
194    {
195        SERVICE_ID.get_or_init(|| std::env::var("FASTLY_SERVICE_ID").unwrap())
196    }
197
198    #[cfg(not(target_env = "p1"))]
199    {
200        SERVICE_ID.get_or_init(wit::compute_runtime::get_service_id)
201    }
202}
203
204/// The version number for the Fastly service that is processing the current request.
205///
206/// Equivalent to the "FASTLY_SERVICE_VERSION" environment variable and to [`req.vcl.version`]
207/// in VCL.
208///
209/// [`req.vcl.version`]: https://www.fastly.com/documentation/reference/vcl/variables/miscellaneous/req-vcl-version/
210pub fn service_version() -> u64 {
211    static SERVICE_VERSION: OnceLock<u64> = OnceLock::new();
212
213    #[cfg(target_env = "p1")]
214    {
215        *SERVICE_VERSION.get_or_init(|| {
216            std::env::var("FASTLY_SERVICE_VERSION")
217                .unwrap()
218                .parse()
219                .unwrap()
220        })
221    }
222
223    #[cfg(not(target_env = "p1"))]
224    {
225        *SERVICE_VERSION.get_or_init(wit::compute_runtime::get_service_version)
226    }
227}
228
229#[doc(hidden)]
230pub fn namespace_id() -> &'static str {
231    static NAMESPACE_ID: OnceLock<String> = OnceLock::new();
232
233    #[cfg(target_env = "p1")]
234    {
235        NAMESPACE_ID.get_or_init(|| std::env::var("FASTLY_NAMESPACE_ID").unwrap())
236    }
237
238    #[cfg(not(target_env = "p1"))]
239    {
240        NAMESPACE_ID.get_or_init(wit::compute_runtime::get_hostname)
241    }
242}
243
244/// A UUID generated by Fastly for each sandbox.
245///
246/// This is often a useful value to include in log messages, and also to send to upstream
247/// servers as an additional custom HTTP header, allowing for straightforward correlation of
248/// which WebAssembly session processed a request to requests later processed by an origin
249/// server. If a session is used to process multiple downstream requests, then you may wish to
250/// use the per-request UUID associated with each individual request handle instead of this
251/// function.
252///
253/// Equivalent to the "FASTLY_TRACE_ID" environment variable.
254pub fn sandbox_id() -> &'static str {
255    static SANDBOX_ID: OnceLock<String> = OnceLock::new();
256
257    // There is no `FASTLY_SANDBOX_ID`, however `FASTLY_TRACE_ID` is a
258    // per-sandbox identifier.
259    #[cfg(target_env = "p1")]
260    {
261        SANDBOX_ID.get_or_init(|| std::env::var("FASTLY_TRACE_ID").unwrap())
262    }
263
264    #[cfg(not(target_env = "p1"))]
265    {
266        SANDBOX_ID.get_or_init(wit::compute_runtime::get_sandbox_id)
267    }
268}