featherbit/plugins/resources.rs
1//! Process-wide services shared by every plugin instance.
2//!
3//! `SharedState` owns one [`PluginResources`] for the process lifetime and
4//! threads it through `compile_policy` → `create_plugin` → each plugin's
5//! `from_config`, so plugins can hold handles to shared infrastructure
6//! (metrics registry, outbound HTTP client, consumer store, rate-limit
7//! counter backends) instead of constructing their own per node or — worse —
8//! per request.
9
10use std::sync::Arc;
11
12use arc_swap::ArcSwap;
13
14use crate::consumers::ConsumerStore;
15use crate::metrics::GatewayMetrics;
16use crate::outbound::OutboundClient;
17use crate::ratelimit::CounterStoreRegistry;
18use crate::traffic::TrafficRegistries;
19
20/// Handle to process-wide services, injected into plugins at construction.
21///
22/// Grows as shared infrastructure lands (counter backends); every field must
23/// be cheap to clone or shared behind its own `Arc`.
24pub struct PluginResources {
25 /// Shared Prometheus registry; `None` disables recording (unit tests).
26 pub metrics: Option<Arc<GatewayMetrics>>,
27 /// Pooled outbound HTTP client for upstream proxying and plugin callouts.
28 pub outbound: Arc<OutboundClient>,
29 /// Consumer store, swapped atomically on config reload so lookups on the
30 /// request path are lock-free. Plugins should `load()` per request, not
31 /// cache the inner Arc across requests.
32 pub consumers: ArcSwap<ConsumerStore>,
33 /// Rate-limit counter backends, resolved by `policy` name at config load.
34 pub counters: CounterStoreRegistry,
35 /// Shared state for traffic-control node pairs (concurrency, breakers, cache).
36 pub traffic: TrafficRegistries,
37}
38
39impl PluginResources {
40 /// Creates the process-wide resources handle with an empty consumer
41 /// store; callers swap in the real store via [`PluginResources::consumers`].
42 pub fn new(metrics: Option<Arc<GatewayMetrics>>) -> Arc<Self> {
43 Arc::new(Self {
44 metrics,
45 outbound: Arc::new(OutboundClient::new()),
46 consumers: ArcSwap::from_pointee(ConsumerStore::default()),
47 counters: CounterStoreRegistry::default(),
48 traffic: TrafficRegistries::default(),
49 })
50 }
51
52 /// Resources with optional services disabled — for unit tests.
53 #[cfg(test)]
54 pub fn empty() -> Arc<Self> {
55 Self::new(None)
56 }
57}