itsi-server 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/exe/itsi +88 -28
  3. data/ext/itsi_error/Cargo.toml +2 -0
  4. data/ext/itsi_error/src/from.rs +70 -0
  5. data/ext/itsi_error/src/lib.rs +10 -37
  6. data/ext/itsi_instrument_entry/Cargo.toml +15 -0
  7. data/ext/itsi_instrument_entry/src/lib.rs +31 -0
  8. data/ext/itsi_rb_helpers/Cargo.toml +2 -0
  9. data/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
  10. data/ext/itsi_rb_helpers/src/lib.rs +90 -10
  11. data/ext/itsi_scheduler/Cargo.toml +24 -0
  12. data/ext/itsi_scheduler/extconf.rb +6 -0
  13. data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  14. data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  15. data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  16. data/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  17. data/ext/itsi_scheduler/src/lib.rs +38 -0
  18. data/ext/itsi_server/Cargo.toml +14 -2
  19. data/ext/itsi_server/extconf.rb +1 -1
  20. data/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  21. data/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  22. data/ext/itsi_server/src/body_proxy/mod.rs +2 -0
  23. data/ext/itsi_server/src/lib.rs +58 -7
  24. data/ext/itsi_server/src/request/itsi_request.rs +238 -104
  25. data/ext/itsi_server/src/response/itsi_response.rs +347 -0
  26. data/ext/itsi_server/src/response/mod.rs +1 -0
  27. data/ext/itsi_server/src/server/bind.rs +50 -20
  28. data/ext/itsi_server/src/server/bind_protocol.rs +37 -0
  29. data/ext/itsi_server/src/server/io_stream.rs +104 -0
  30. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
  31. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
  32. data/ext/itsi_server/src/server/itsi_server.rs +196 -134
  33. data/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
  34. data/ext/itsi_server/src/server/listener.rs +184 -127
  35. data/ext/itsi_server/src/server/mod.rs +7 -1
  36. data/ext/itsi_server/src/server/process_worker.rs +196 -0
  37. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
  38. data/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  39. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
  40. data/ext/itsi_server/src/server/signal.rs +70 -0
  41. data/ext/itsi_server/src/server/thread_worker.rs +368 -0
  42. data/ext/itsi_server/src/server/tls.rs +42 -28
  43. data/ext/itsi_tracing/Cargo.toml +4 -0
  44. data/ext/itsi_tracing/src/lib.rs +36 -6
  45. data/lib/itsi/request.rb +30 -14
  46. data/lib/itsi/server/rack/handler/itsi.rb +25 -0
  47. data/lib/itsi/server/scheduler_mode.rb +6 -0
  48. data/lib/itsi/server/version.rb +1 -1
  49. data/lib/itsi/server.rb +82 -2
  50. data/lib/itsi/signals.rb +23 -0
  51. data/lib/itsi/stream_io.rb +38 -0
  52. metadata +38 -25
  53. data/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
  54. data/ext/itsi_server/src/stream_writer/mod.rs +0 -21
@@ -1,52 +1,5 @@
1
1
  -----BEGIN PRIVATE KEY-----
2
- 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
- 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
- +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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- FOQCz2FMVXUgUiAk0/kLERuRavkVwVhQoCikWEMp9CRcYIoSfizfC42pS7MQR0RL
13
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
51
- cN5973/E4MpAKMt1shs0YWr3axraOhkg
2
+ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgC7WOxDmO7pBvDvYn
3
+ YI8+z2/2c0ChxBsuJkQq/dXi1RyhRANCAASoZ0L1WLWvsBG+pKQ9eQCCJXmCfYwx
4
+ N4Rp9qCtZPsbWidKH8b5Cy3GXrWR8U0s5OLLo1KAC0ob6B+94JOjQ9zP
52
5
  -----END PRIVATE KEY-----
@@ -1,56 +1,111 @@
1
1
  use super::{
2
2
  bind::Bind,
3
- listener::{Listener, SockAddr},
3
+ listener::Listener,
4
+ serve_strategy::{cluster_mode::ClusterMode, single_mode::SingleMode},
5
+ signal::{clear_signal_handlers, reset_signal_handlers, SIGNAL_HANDLER_CHANNEL},
4
6
  };
5
- use crate::{request::itsi_request::ItsiRequest, ITSI_SERVER};
6
- use bytes::Bytes;
7
+ use crate::{request::itsi_request::ItsiRequest, server::serve_strategy::ServeStrategy};
7
8
  use derive_more::Debug;
8
- use http_body_util::{combinators::BoxBody, Empty};
9
- use hyper::{
10
- body::Incoming, header::HeaderName, service::service_fn, HeaderMap, Request, Response,
11
- StatusCode,
12
- };
13
- use hyper_util::{rt::TokioExecutor, server::conn::auto::Builder};
14
- use itsi_tracing::{error, info};
9
+ use itsi_rb_helpers::call_without_gvl;
10
+ use itsi_tracing::error;
15
11
  use magnus::{
12
+ block::Proc,
16
13
  error::Result,
17
14
  scan_args::{get_kwargs, scan_args, Args, KwArgs},
18
- value::{Opaque, ReprValue},
19
- RHash, Ruby, Value,
15
+ value::{InnerValue, Opaque, ReprValue},
16
+ RHash, Ruby, Symbol, Value,
20
17
  };
21
18
  use parking_lot::Mutex;
22
- use std::{collections::HashMap, convert::Infallible, sync::Arc};
23
- use tokio::runtime::Builder as RuntimeBuilder;
24
- use tokio::task::JoinSet;
19
+ use std::{cmp::max, ops::Deref, sync::Arc};
20
+ use tracing::{info, instrument};
21
+
22
+ static DEFAULT_BIND: &str = "localhost:3000";
25
23
 
26
24
  #[magnus::wrap(class = "Itsi::Server", free_immediately, size)]
27
- #[derive(Debug)]
25
+ #[derive(Clone)]
28
26
  pub struct Server {
27
+ pub config: Arc<ServerConfig>,
28
+ }
29
+
30
+ impl Deref for Server {
31
+ type Target = ServerConfig;
32
+
33
+ fn deref(&self) -> &Self::Target {
34
+ &self.config
35
+ }
36
+ }
37
+ type AfterFork = Mutex<Arc<Option<Box<dyn Fn() + Send + Sync>>>>;
38
+
39
+ #[derive(Debug)]
40
+ pub struct ServerConfig {
29
41
  #[debug(skip)]
30
- app: Opaque<Value>,
42
+ pub app: Opaque<Value>,
31
43
  #[allow(unused)]
32
- workers: u16,
44
+ pub workers: u8,
33
45
  #[allow(unused)]
34
- threads: u16,
46
+ pub threads: u8,
35
47
  #[allow(unused)]
36
- shutdown_timeout: f64,
37
- script_name: String,
48
+ pub shutdown_timeout: f64,
49
+ pub script_name: String,
38
50
  pub(crate) binds: Mutex<Vec<Bind>>,
51
+ #[debug(skip)]
52
+ pub before_fork: Mutex<Option<Box<dyn FnOnce() + Send + Sync>>>,
53
+ #[debug(skip)]
54
+ pub after_fork: AfterFork,
55
+ pub scheduler_class: Option<String>,
56
+ pub stream_body: Option<bool>,
57
+ pub worker_memory_limit: Option<u64>,
58
+ }
59
+
60
+ #[derive(Debug)]
61
+ pub enum RequestJob {
62
+ ProcessRequest(ItsiRequest),
63
+ Shutdown,
39
64
  }
40
65
 
41
66
  impl Server {
67
+ #[instrument(
68
+ name = "Itsi",
69
+ parent=None,
70
+ skip(args),
71
+ fields(workers = 1, threads = 1, shutdown_timeout = 5)
72
+ )]
42
73
  pub fn new(args: &[Value]) -> Result<Self> {
43
- type OptionalArgs = (
44
- Option<u16>,
45
- Option<u16>,
74
+ let scan_args: Args<(), (), (), (), RHash, ()> = scan_args(args)?;
75
+
76
+ type ArgSet1 = (
77
+ Option<u8>,
78
+ Option<u8>,
46
79
  Option<f64>,
47
80
  Option<String>,
48
81
  Option<Vec<String>>,
82
+ Option<Proc>,
83
+ Option<Proc>,
84
+ Option<String>,
85
+ Option<bool>,
49
86
  );
50
87
 
51
- let scan_args: Args<(), (), (), (), RHash, ()> = scan_args(args)?;
52
- let args: KwArgs<(Value,), OptionalArgs, ()> = get_kwargs(
53
- scan_args.keywords,
88
+ type ArgSet2 = (Option<u64>,);
89
+
90
+ let args1: KwArgs<(Value,), ArgSet1, ()> = get_kwargs(
91
+ scan_args
92
+ .keywords
93
+ .funcall::<_, _, RHash>(
94
+ "slice",
95
+ (
96
+ Symbol::new("app"),
97
+ Symbol::new("workers"),
98
+ Symbol::new("threads"),
99
+ Symbol::new("shutdown_timeout"),
100
+ Symbol::new("script_name"),
101
+ Symbol::new("binds"),
102
+ Symbol::new("before_fork"),
103
+ Symbol::new("after_fork"),
104
+ Symbol::new("scheduler_class"),
105
+ Symbol::new("stream_body"),
106
+ ),
107
+ )
108
+ .unwrap(),
54
109
  &["app"],
55
110
  &[
56
111
  "workers",
@@ -58,125 +113,132 @@ impl Server {
58
113
  "shutdown_timeout",
59
114
  "script_name",
60
115
  "binds",
116
+ "before_fork",
117
+ "after_fork",
118
+ "scheduler_class",
119
+ "stream_body",
61
120
  ],
62
121
  )?;
63
- let server = Server {
64
- app: Opaque::from(args.required.0),
65
- workers: args.optional.0.unwrap_or(1),
66
- threads: args.optional.1.unwrap_or(1),
67
- shutdown_timeout: args.optional.2.unwrap_or(5.0),
68
- script_name: args.optional.3.unwrap_or("".to_string()),
122
+
123
+ let args2: KwArgs<(), ArgSet2, ()> = get_kwargs(
124
+ scan_args
125
+ .keywords
126
+ .funcall::<_, _, RHash>("slice", (Symbol::new("worker_memory_limit"),))
127
+ .unwrap(),
128
+ &[],
129
+ &["worker_memory_limit"],
130
+ )?;
131
+
132
+ let config = ServerConfig {
133
+ app: Opaque::from(args1.required.0),
134
+ workers: max(args1.optional.0.unwrap_or(1), 1),
135
+ threads: max(args1.optional.1.unwrap_or(1), 1),
136
+ shutdown_timeout: args1.optional.2.unwrap_or(5.0),
137
+ script_name: args1.optional.3.unwrap_or("".to_string()),
69
138
  binds: Mutex::new(
70
- args.optional
139
+ args1
140
+ .optional
71
141
  .4
72
- .unwrap_or_else(|| vec!["localhost:3000".to_string()])
142
+ .unwrap_or_else(|| vec![DEFAULT_BIND.to_string()])
73
143
  .into_iter()
74
- .map(|s| s.parse().unwrap_or_else(|_| Bind::default()))
75
- .collect(),
144
+ .map(|s| s.parse())
145
+ .collect::<itsi_error::Result<Vec<Bind>>>()?,
76
146
  ),
147
+ before_fork: Mutex::new(args1.optional.5.map(|p| {
148
+ let opaque_proc = Opaque::from(p);
149
+ Box::new(move || {
150
+ opaque_proc
151
+ .get_inner_with(&Ruby::get().unwrap())
152
+ .call::<_, Value>(())
153
+ .unwrap();
154
+ }) as Box<dyn FnOnce() + Send + Sync>
155
+ })),
156
+ after_fork: Mutex::new(Arc::new(args1.optional.6.map(|p| {
157
+ let opaque_proc = Opaque::from(p);
158
+ Box::new(move || {
159
+ opaque_proc
160
+ .get_inner_with(&Ruby::get().unwrap())
161
+ .call::<_, Value>(())
162
+ .unwrap();
163
+ }) as Box<dyn Fn() + Send + Sync>
164
+ }))),
165
+ scheduler_class: args1.optional.7.clone(),
166
+ stream_body: args1.optional.8,
167
+ worker_memory_limit: args2.optional.0,
77
168
  };
78
- Ok(server)
79
- }
80
169
 
81
- pub(crate) async fn process_request(
82
- hyper_request: Request<Incoming>,
83
- app: Opaque<Value>,
84
- script_name: String,
85
- listener: Arc<Listener>,
86
- addr: SockAddr,
87
- ) -> itsi_error::Result<Response<BoxBody<Bytes, Infallible>>> {
88
- let request = ItsiRequest::build_from(hyper_request, addr, script_name, listener).await;
89
- let ruby = Ruby::get().unwrap();
90
- let server = ruby.get_inner(&ITSI_SERVER);
91
- let response: Result<(u16, HashMap<String, String>, Value)> =
92
- server.funcall("call", (app, request));
93
- if let Ok((status, headers_raw, body)) = response {
94
- let mut body_buf = vec![];
95
- for body_chunk in body.enumeratorize("each", ()) {
96
- body_buf.push(body_chunk.unwrap().to_string())
97
- }
98
- body.check_funcall::<_, _, Value>("close", ());
99
- let boxed_body = BoxBody::new(body_buf.join(""));
100
- let mut response = Response::new(boxed_body);
101
- let mut headers = HeaderMap::new();
102
- headers_raw.into_iter().for_each(|(key, value)| {
103
- let header_name: HeaderName = key.parse().unwrap();
104
- headers.insert(header_name, value.parse().unwrap());
105
- });
106
- *response.headers_mut() = headers;
107
- *response.status_mut() = StatusCode::from_u16(status).unwrap();
108
- Ok(response)
170
+ if let Some(scheduler_class) = args1.optional.7 {
171
+ info!(scheduler_class, fiber_scheduler = true);
109
172
  } else {
110
- let mut response = Response::new(BoxBody::new(Empty::new()));
111
- *response.status_mut() = StatusCode::BAD_REQUEST;
112
- Ok(response)
173
+ info!(fiber_scheduler = false);
113
174
  }
175
+
176
+ Ok(Server {
177
+ config: Arc::new(config),
178
+ })
114
179
  }
115
180
 
116
- pub fn start(&self) {
117
- let mut builder: RuntimeBuilder = RuntimeBuilder::new_current_thread();
118
- let runtime = builder
119
- .thread_name("itsi-server-accept-loop")
120
- .thread_stack_size(3 * 1024 * 1024)
121
- .enable_io()
122
- .enable_time()
123
- .build()
124
- .expect("Failed to build Tokio runtime");
125
-
126
- runtime.block_on(async {
127
- let server = Arc::new(Builder::new(TokioExecutor::new()));
128
- let listeners: Vec<Listener> = self
129
- .binds
130
- .lock()
131
- .iter()
132
- .cloned()
133
- .map(Listener::from)
134
- .collect::<Vec<_>>();
135
-
136
- let mut set = JoinSet::new();
137
-
138
- for listener in listeners {
139
- let app = self.app;
140
- let server_clone = server.clone();
141
- let listener_clone = Arc::new(listener);
142
- let script_name = self.script_name.clone();
143
-
144
- set.spawn(async move {
145
- loop {
146
- let server = server_clone.clone();
147
- let listener = listener_clone.clone();
148
- let script_name = script_name.clone();
149
- let (stream, addr) = match listener.accept().await {
150
- Ok(stream) => stream,
151
- Err(e) => {
152
- error!("Failed to accept connection: {:?}", e);
153
- continue;
154
- }
155
- };
156
-
157
- tokio::spawn(async move {
158
- if let Err(e) = server
159
- .serve_connection_with_upgrades(
160
- stream,
161
- service_fn(move |hyper_request: Request<Incoming>| {
162
- Server::process_request(
163
- hyper_request,
164
- app,
165
- script_name.clone(),
166
- listener.clone(),
167
- addr.clone(),
168
- )
169
- }),
170
- )
171
- .await
172
- {
173
- info!("Closed connection due to: {:?}", e);
174
- }
175
- });
176
- }
177
- });
181
+ #[instrument(name = "Bind", skip_all, fields(binds=format!("{:?}", self.config.binds.lock())))]
182
+ pub(crate) fn listeners(&self) -> Result<Arc<Vec<Arc<Listener>>>> {
183
+ let listeners = self
184
+ .config
185
+ .binds
186
+ .lock()
187
+ .iter()
188
+ .cloned()
189
+ .map(Listener::try_from)
190
+ .collect::<std::result::Result<Vec<Listener>, _>>()?
191
+ .into_iter()
192
+ .map(Arc::new)
193
+ .collect::<Vec<_>>();
194
+ info!("Bound {:?} listeners", listeners.len());
195
+ Ok(Arc::new(listeners))
196
+ }
197
+
198
+ pub(crate) fn build_strategy(
199
+ self,
200
+ listeners: Arc<Vec<Arc<Listener>>>,
201
+ ) -> Result<ServeStrategy> {
202
+ let server = Arc::new(self);
203
+
204
+ let strategy = if server.config.workers == 1 {
205
+ ServeStrategy::Single(Arc::new(SingleMode::new(
206
+ server,
207
+ listeners,
208
+ SIGNAL_HANDLER_CHANNEL.0.clone(),
209
+ )?))
210
+ } else {
211
+ ServeStrategy::Cluster(Arc::new(ClusterMode::new(
212
+ server,
213
+ listeners,
214
+ SIGNAL_HANDLER_CHANNEL.0.clone(),
215
+ )))
216
+ };
217
+ Ok(strategy)
218
+ }
219
+
220
+ pub fn start(&self) -> Result<()> {
221
+ reset_signal_handlers();
222
+ let rself = self.clone();
223
+ let listeners = self.listeners()?;
224
+ let listeners_clone = listeners.clone();
225
+ call_without_gvl(move || -> Result<()> {
226
+ let strategy = rself.build_strategy(listeners_clone)?;
227
+ if let Err(e) = strategy.run() {
228
+ error!("Error running server: {}", e);
229
+ strategy.stop()?;
178
230
  }
179
- while let Some(_res) = set.join_next().await {}
180
- })
231
+ drop(strategy);
232
+ Ok(())
233
+ })?;
234
+ if let Ok(listeners) = Arc::try_unwrap(listeners) {
235
+ listeners.into_iter().for_each(|listener| {
236
+ if let Ok(listener) = Arc::try_unwrap(listener) {
237
+ listener.unbind()
238
+ };
239
+ });
240
+ }
241
+ clear_signal_handlers();
242
+ Ok(())
181
243
  }
182
244
  }
@@ -0,0 +1,9 @@
1
+ #[derive(Debug, Clone)]
2
+ pub enum LifecycleEvent {
3
+ Start,
4
+ Shutdown,
5
+ Restart,
6
+ IncreaseWorkers,
7
+ DecreaseWorkers,
8
+ ForceShutdown,
9
+ }