itsi-scheduler 0.2.16 → 0.2.18

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1 -1
  3. data/ext/itsi_acme/Cargo.toml +1 -1
  4. data/ext/itsi_scheduler/Cargo.toml +1 -1
  5. data/ext/itsi_server/Cargo.toml +3 -1
  6. data/ext/itsi_server/src/lib.rs +6 -1
  7. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +2 -0
  8. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +4 -4
  9. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +14 -13
  10. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +64 -33
  11. data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +151 -152
  12. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +422 -110
  13. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +62 -15
  14. data/ext/itsi_server/src/ruby_types/itsi_server.rs +1 -1
  15. data/ext/itsi_server/src/server/binds/listener.rs +45 -7
  16. data/ext/itsi_server/src/server/frame_stream.rs +142 -0
  17. data/ext/itsi_server/src/server/http_message_types.rs +142 -9
  18. data/ext/itsi_server/src/server/io_stream.rs +28 -5
  19. data/ext/itsi_server/src/server/lifecycle_event.rs +1 -1
  20. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +2 -3
  21. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +8 -10
  22. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +2 -3
  23. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +3 -3
  24. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +54 -56
  25. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +5 -7
  26. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +5 -5
  27. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +7 -10
  28. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +2 -3
  29. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +1 -2
  30. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +4 -6
  31. data/ext/itsi_server/src/server/mod.rs +1 -0
  32. data/ext/itsi_server/src/server/process_worker.rs +3 -4
  33. data/ext/itsi_server/src/server/serve_strategy/acceptor.rs +16 -12
  34. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +83 -31
  35. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +166 -142
  36. data/ext/itsi_server/src/server/signal.rs +37 -9
  37. data/ext/itsi_server/src/server/thread_worker.rs +84 -69
  38. data/ext/itsi_server/src/services/itsi_http_service.rs +43 -43
  39. data/ext/itsi_server/src/services/static_file_server.rs +28 -47
  40. data/lib/itsi/scheduler/version.rb +1 -1
  41. metadata +2 -1
@@ -1,5 +1,5 @@
1
1
  use crate::{
2
- server::http_message_types::{HttpRequest, HttpResponse},
2
+ server::http_message_types::{HttpBody, HttpRequest, HttpResponse},
3
3
  services::itsi_http_service::HttpRequestContext,
4
4
  };
5
5
 
@@ -20,8 +20,8 @@ use http::{
20
20
  header::{GetAll, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TYPE},
21
21
  HeaderValue, Response,
22
22
  };
23
- use http_body_util::{combinators::BoxBody, BodyExt, Full, StreamBody};
24
- use hyper::body::{Body, Frame};
23
+ use http_body_util::{BodyExt, StreamBody};
24
+ use hyper::body::Body;
25
25
  use magnus::error::Result;
26
26
  use serde::{Deserialize, Serialize};
27
27
  use std::convert::Infallible;
@@ -126,15 +126,13 @@ impl MimeType {
126
126
  }
127
127
  }
128
128
 
129
- fn stream_encode<R>(encoder: R) -> BoxBody<Bytes, Infallible>
129
+ fn stream_encode<R>(encoder: R) -> HttpBody
130
130
  where
131
131
  R: AsyncRead + Unpin + Sync + Send + 'static,
132
132
  {
133
- let encoded_stream = ReaderStream::new(encoder).map(|res| {
134
- res.map(Frame::data)
135
- .map_err(|_| -> Infallible { unreachable!("We handle IO errors above") })
136
- });
137
- BoxBody::new(StreamBody::new(encoded_stream))
133
+ let encoded_stream = ReaderStream::new(encoder)
134
+ .map(|res| res.map_err(|_| -> Infallible { unreachable!("We handle IO errors above") }));
135
+ HttpBody::stream(StreamBody::new(encoded_stream))
138
136
  }
139
137
 
140
138
  fn update_content_encoding(parts: &mut http::response::Parts, new_encoding: HeaderValue) {
@@ -293,7 +291,7 @@ impl MiddlewareLayer for Compression {
293
291
  }
294
292
  CompressionAlgorithm::Identity => unreachable!(),
295
293
  };
296
- BoxBody::new(Full::new(Bytes::from(compressed_bytes)))
294
+ HttpBody::full(Bytes::from(compressed_bytes))
297
295
  } else {
298
296
  let stream = body
299
297
  .into_data_stream()
@@ -1,12 +1,11 @@
1
1
  use super::{FromValue, MiddlewareLayer};
2
2
  use crate::{
3
- server::http_message_types::{HttpRequest, HttpResponse, RequestExt},
3
+ server::http_message_types::{HttpBody, HttpRequest, HttpResponse, RequestExt},
4
4
  services::itsi_http_service::HttpRequestContext,
5
5
  };
6
6
 
7
7
  use async_trait::async_trait;
8
8
  use http::{HeaderMap, Method, Response};
9
- use http_body_util::{combinators::BoxBody, Empty};
10
9
  use itsi_error::ItsiError;
11
10
  use magnus::error::Result;
12
11
  use serde::Deserialize;
@@ -273,7 +272,7 @@ impl MiddlewareLayer for Cors {
273
272
  let mut response_builder = Response::builder().status(204);
274
273
  *response_builder.headers_mut().unwrap() = headers;
275
274
  let response = response_builder
276
- .body(BoxBody::new(Empty::new()))
275
+ .body(HttpBody::empty())
277
276
  .map_err(ItsiError::new)?;
278
277
  return Ok(either::Either::Right(response));
279
278
  }
@@ -1,6 +1,6 @@
1
1
  use super::FromValue;
2
2
  use crate::{
3
- server::http_message_types::{HttpRequest, HttpResponse},
3
+ server::http_message_types::{HttpBody, HttpRequest, HttpResponse},
4
4
  services::itsi_http_service::HttpRequestContext,
5
5
  };
6
6
  use async_trait::async_trait;
@@ -8,7 +8,7 @@ use bytes::{Bytes, BytesMut};
8
8
  use either::Either;
9
9
  use futures::TryStreamExt;
10
10
  use http::{HeaderValue, StatusCode};
11
- use http_body_util::{combinators::BoxBody, BodyExt, Empty};
11
+ use http_body_util::BodyExt;
12
12
  use itsi_error::ItsiError;
13
13
  use serde::{Deserialize, Serialize};
14
14
  use std::sync::Arc;
@@ -164,7 +164,7 @@ impl super::MiddlewareLayer for Csp {
164
164
  }
165
165
  }
166
166
 
167
- let mut resp = HttpResponse::new(BoxBody::new(Empty::new()));
167
+ let mut resp = HttpResponse::new(HttpBody::empty());
168
168
  *resp.status_mut() = StatusCode::NO_CONTENT;
169
169
  return Ok(Either::Right(resp));
170
170
  }
@@ -1,91 +1,89 @@
1
1
  use super::{ContentSource, DefaultFormat, ErrorResponse};
2
- use crate::server::http_message_types::ResponseFormat;
2
+ use crate::server::http_message_types::{HttpBody, ResponseFormat};
3
3
  use bytes::Bytes;
4
- use http_body_util::{combinators::BoxBody, Full};
5
- use std::convert::Infallible;
6
4
 
7
5
  impl DefaultFormat {
8
6
  pub fn response_for_code(&self, code: u16) -> ContentSource {
9
7
  match self {
10
8
  DefaultFormat::Plaintext => match code {
11
- 500 => ContentSource::Static(Full::new("500 Internal Error".into())),
12
- 404 => ContentSource::Static(Full::new("404 Not Found".into())),
13
- 401 => ContentSource::Static(Full::new("401 Unauthorized".into())),
14
- 403 => ContentSource::Static(Full::new("403 Forbidden".into())),
15
- 413 => ContentSource::Static(Full::new("413 Payload Too Large".into())),
16
- 429 => ContentSource::Static(Full::new("429 Too Many Requests".into())),
17
- 502 => ContentSource::Static(Full::new("502 Bad Gateway".into())),
18
- 503 => ContentSource::Static(Full::new("503 Service Unavailable".into())),
19
- 504 => ContentSource::Static(Full::new("504 Gateway Timeout".into())),
20
- _ => ContentSource::Static(Full::new("Unexpected Error".into())),
9
+ 500 => ContentSource::Static("500 Internal Error".into()),
10
+ 404 => ContentSource::Static("404 Not Found".into()),
11
+ 401 => ContentSource::Static("401 Unauthorized".into()),
12
+ 403 => ContentSource::Static("403 Forbidden".into()),
13
+ 413 => ContentSource::Static("413 Payload Too Large".into()),
14
+ 429 => ContentSource::Static("429 Too Many Requests".into()),
15
+ 502 => ContentSource::Static("502 Bad Gateway".into()),
16
+ 503 => ContentSource::Static("503 Service Unavailable".into()),
17
+ 504 => ContentSource::Static("504 Gateway Timeout".into()),
18
+ _ => ContentSource::Static("Unexpected Error".into()),
21
19
  },
22
20
  DefaultFormat::Html => match code {
23
- 500 => ContentSource::Static(Full::new(
21
+ 500 => ContentSource::Static(
24
22
  include_str!("../../../../default_responses/html/500.html").into(),
25
- )),
26
- 404 => ContentSource::Static(Full::new(
23
+ ),
24
+ 404 => ContentSource::Static(
27
25
  include_str!("../../../../default_responses/html/404.html").into(),
28
- )),
29
- 401 => ContentSource::Static(Full::new(
26
+ ),
27
+ 401 => ContentSource::Static(
30
28
  include_str!("../../../../default_responses/html/401.html").into(),
31
- )),
32
- 403 => ContentSource::Static(Full::new(
29
+ ),
30
+ 403 => ContentSource::Static(
33
31
  include_str!("../../../../default_responses/html/403.html").into(),
34
- )),
35
- 413 => ContentSource::Static(Full::new(
32
+ ),
33
+ 413 => ContentSource::Static(
36
34
  include_str!("../../../../default_responses/html/413.html").into(),
37
- )),
38
- 429 => ContentSource::Static(Full::new(
35
+ ),
36
+ 429 => ContentSource::Static(
39
37
  include_str!("../../../../default_responses/html/429.html").into(),
40
- )),
41
- 502 => ContentSource::Static(Full::new(
38
+ ),
39
+ 502 => ContentSource::Static(
42
40
  include_str!("../../../../default_responses/html/502.html").into(),
43
- )),
44
- 503 => ContentSource::Static(Full::new(
41
+ ),
42
+ 503 => ContentSource::Static(
45
43
  include_str!("../../../../default_responses/html/503.html").into(),
46
- )),
47
- 504 => ContentSource::Static(Full::new(
44
+ ),
45
+ 504 => ContentSource::Static(
48
46
  include_str!("../../../../default_responses/html/504.html").into(),
49
- )),
50
- _ => ContentSource::Static(Full::new(
47
+ ),
48
+ _ => ContentSource::Static(
51
49
  include_str!("../../../../default_responses/html/500.html").into(),
52
- )),
50
+ ),
53
51
  },
54
52
  DefaultFormat::Json => match code {
55
- 500 => ContentSource::Static(Full::new(
53
+ 500 => ContentSource::Static(
56
54
  include_str!("../../../../default_responses/json/500.json").into(),
57
- )),
58
- 404 => ContentSource::Static(Full::new(
55
+ ),
56
+ 404 => ContentSource::Static(
59
57
  include_str!("../../../../default_responses/json/404.json").into(),
60
- )),
61
- 401 => ContentSource::Static(Full::new(
58
+ ),
59
+ 401 => ContentSource::Static(
62
60
  include_str!("../../../../default_responses/json/401.json").into(),
63
- )),
64
- 403 => ContentSource::Static(Full::new(
61
+ ),
62
+ 403 => ContentSource::Static(
65
63
  include_str!("../../../../default_responses/json/403.json").into(),
66
- )),
67
- 413 => ContentSource::Static(Full::new(
64
+ ),
65
+ 413 => ContentSource::Static(
68
66
  include_str!("../../../../default_responses/json/413.json").into(),
69
- )),
70
- 429 => ContentSource::Static(Full::new(
67
+ ),
68
+ 429 => ContentSource::Static(
71
69
  include_str!("../../../../default_responses/json/429.json").into(),
72
- )),
73
- 502 => ContentSource::Static(Full::new(
70
+ ),
71
+ 502 => ContentSource::Static(
74
72
  include_str!("../../../../default_responses/json/502.json").into(),
75
- )),
76
- 503 => ContentSource::Static(Full::new(
73
+ ),
74
+ 503 => ContentSource::Static(
77
75
  include_str!("../../../../default_responses/json/503.json").into(),
78
- )),
79
- 504 => ContentSource::Static(Full::new(
76
+ ),
77
+ 504 => ContentSource::Static(
80
78
  include_str!("../../../../default_responses/json/504.json").into(),
81
- )),
82
- _ => ContentSource::Static(Full::new("Unexpected Error".into())),
79
+ ),
80
+ _ => ContentSource::Static("Unexpected Error".into()),
83
81
  },
84
82
  }
85
83
  }
86
84
  }
87
85
  impl ErrorResponse {
88
- pub fn fallback_body_for(code: u16, accept: ResponseFormat) -> BoxBody<Bytes, Infallible> {
86
+ pub fn fallback_body_for(code: u16, accept: ResponseFormat) -> HttpBody {
89
87
  let source = match accept {
90
88
  ResponseFormat::TEXT => DefaultFormat::Plaintext.response_for_code(code),
91
89
  ResponseFormat::HTML => DefaultFormat::Html.response_for_code(code),
@@ -93,9 +91,9 @@ impl ErrorResponse {
93
91
  ResponseFormat::UNKNOWN => ContentSource::Inline("Unexpected Error".to_owned()),
94
92
  };
95
93
  match source {
96
- ContentSource::Inline(bytes) => BoxBody::new(Full::new(Bytes::from(bytes))),
97
- ContentSource::Static(bytes) => BoxBody::new(bytes),
98
- ContentSource::File(_) => BoxBody::new(Full::new(Bytes::from("Unexpected error"))),
94
+ ContentSource::Inline(bytes) => HttpBody::full(Bytes::from(bytes)),
95
+ ContentSource::Static(bytes) => HttpBody::full(bytes),
96
+ ContentSource::File(_) => HttpBody::full(Bytes::from("Unexpected error")),
99
97
  }
100
98
  }
101
99
  pub fn internal_server_error() -> Self {
@@ -1,13 +1,11 @@
1
1
  use bytes::Bytes;
2
2
  use http::header::CONTENT_TYPE;
3
3
  use http::Response;
4
- use http_body_util::{combinators::BoxBody, Full};
5
4
  use serde::{Deserialize, Deserializer};
6
- use std::convert::Infallible;
7
5
  use std::path::PathBuf;
8
6
  use tracing::warn;
9
7
 
10
- use crate::server::http_message_types::{HttpResponse, ResponseFormat};
8
+ use crate::server::http_message_types::{HttpBody, HttpResponse, ResponseFormat};
11
9
  use crate::services::static_file_server::ROOT_STATIC_FILE_SERVER;
12
10
  mod default_responses;
13
11
 
@@ -19,7 +17,7 @@ pub enum ContentSource {
19
17
  File(PathBuf),
20
18
  #[serde(rename(deserialize = "static"))]
21
19
  #[serde(skip_deserializing)]
22
- Static(Full<Bytes>),
20
+ Static(Bytes),
23
21
  }
24
22
 
25
23
  #[derive(Debug, Clone, Deserialize, Default)]
@@ -144,13 +142,13 @@ impl ErrorResponse {
144
142
  code: u16,
145
143
  source: &Option<ContentSource>,
146
144
  accept: ResponseFormat,
147
- ) -> BoxBody<Bytes, Infallible> {
145
+ ) -> HttpBody {
148
146
  match source {
149
147
  Some(ContentSource::Inline(text)) => {
150
- return BoxBody::new(Full::new(Bytes::from(text.clone())));
148
+ return HttpBody::full(Bytes::from(text.clone()));
151
149
  }
152
150
  Some(ContentSource::Static(text)) => {
153
- return BoxBody::new(text.clone());
151
+ return HttpBody::full(text.clone());
154
152
  }
155
153
  Some(ContentSource::File(path)) => {
156
154
  // Convert the PathBuf to a &str (assumes valid UTF-8).
@@ -1,5 +1,5 @@
1
1
  use crate::{
2
- server::http_message_types::{HttpRequest, HttpResponse},
2
+ server::http_message_types::{HttpBody, HttpRequest, HttpResponse},
3
3
  services::itsi_http_service::HttpRequestContext,
4
4
  };
5
5
 
@@ -10,7 +10,7 @@ use bytes::{Bytes, BytesMut};
10
10
  use either::Either;
11
11
  use futures::TryStreamExt;
12
12
  use http::{header, HeaderValue, Response, StatusCode};
13
- use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
13
+ use http_body_util::BodyExt;
14
14
  use hyper::body::Body;
15
15
  use magnus::error::Result;
16
16
  use serde::Deserialize;
@@ -113,7 +113,7 @@ impl MiddlewareLayer for ETag {
113
113
  .await
114
114
  {
115
115
  Ok(bytes_mut) => bytes_mut.freeze(),
116
- Err(_) => return Response::from_parts(parts, BoxBody::new(Empty::new())),
116
+ Err(_) => return Response::from_parts(parts, HttpBody::empty()),
117
117
  };
118
118
 
119
119
  let computed_etag = match self.algorithm {
@@ -139,14 +139,14 @@ impl MiddlewareLayer for ETag {
139
139
  parts.headers.insert(header::ETAG, value);
140
140
  }
141
141
 
142
- body = Full::new(full_bytes).boxed();
142
+ body = HttpBody::full(full_bytes);
143
143
  formatted_etag
144
144
  };
145
145
 
146
146
  if let Some(if_none_match) = context.get_if_none_match() {
147
147
  if if_none_match == etag_value || if_none_match == "*" {
148
148
  // Return 304 Not Modified without the body
149
- let mut not_modified = Response::new(BoxBody::new(Empty::new()));
149
+ let mut not_modified = Response::new(HttpBody::empty());
150
150
  *not_modified.status_mut() = StatusCode::NOT_MODIFIED;
151
151
  // Copy headers we want to preserve
152
152
  for (name, value) in parts.headers.iter() {
@@ -14,7 +14,7 @@ use super::{string_rewrite::StringRewrite, ErrorResponse, FromValue, MiddlewareL
14
14
  use crate::{
15
15
  server::{
16
16
  binds::bind::{Bind, BindAddress},
17
- http_message_types::{HttpRequest, HttpResponse, RequestExt, ResponseFormat},
17
+ http_message_types::{HttpBody, HttpRequest, HttpResponse, RequestExt, ResponseFormat},
18
18
  size_limited_incoming::MaxBodySizeReached,
19
19
  },
20
20
  services::itsi_http_service::HttpRequestContext,
@@ -24,8 +24,7 @@ use bytes::{Bytes, BytesMut};
24
24
  use either::Either;
25
25
  use futures::TryStreamExt;
26
26
  use http::{HeaderMap, Method, Response, StatusCode};
27
- use http_body_util::{combinators::BoxBody, BodyExt, Empty, StreamBody};
28
- use hyper::body::Frame;
27
+ use http_body_util::BodyExt;
29
28
  use magnus::error::Result;
30
29
  use rand::Rng;
31
30
  use reqwest::{
@@ -373,19 +372,17 @@ impl MiddlewareLayer for Proxy {
373
372
  for (hn, hv) in response.headers() {
374
373
  builder = builder.header(hn, hv);
375
374
  }
376
- let response = builder.body(BoxBody::new(StreamBody::new(
377
- response
378
- .bytes_stream()
379
- .map_ok(Frame::data)
380
- .map_err(|_| -> Infallible { unreachable!("We handle IO errors above") }),
381
- )));
375
+ let response =
376
+ builder.body(HttpBody::stream(response.bytes_stream().map_err(
377
+ |_| -> Infallible { unreachable!("We handle IO errors above") },
378
+ )));
382
379
  response.unwrap_or(error_response)
383
380
  }
384
381
  Err(e) => {
385
382
  debug!(target: "middleware::proxy", "Error {:?} received", e);
386
383
  if let Some(inner) = e.source() {
387
384
  if inner.downcast_ref::<MaxBodySizeReached>().is_some() {
388
- let mut max_body_response = Response::new(BoxBody::new(Empty::new()));
385
+ let mut max_body_response = Response::new(HttpBody::empty());
389
386
  *max_body_response.status_mut() = StatusCode::PAYLOAD_TOO_LARGE;
390
387
  return Ok(Either::Right(max_body_response));
391
388
  }
@@ -1,7 +1,7 @@
1
1
  use super::{string_rewrite::StringRewrite, FromValue, MiddlewareLayer};
2
2
  use crate::{
3
3
  server::{
4
- http_message_types::{HttpRequest, HttpResponse},
4
+ http_message_types::{HttpBody, HttpRequest, HttpResponse},
5
5
  redirect_type::RedirectType,
6
6
  },
7
7
  services::itsi_http_service::HttpRequestContext,
@@ -9,7 +9,6 @@ use crate::{
9
9
  use async_trait::async_trait;
10
10
  use either::Either;
11
11
  use http::Response;
12
- use http_body_util::{combinators::BoxBody, Empty};
13
12
  use magnus::error::Result;
14
13
  use serde::Deserialize;
15
14
  use tracing::debug;
@@ -39,7 +38,7 @@ impl Redirect {
39
38
  req: &HttpRequest,
40
39
  context: &mut HttpRequestContext,
41
40
  ) -> Result<HttpResponse> {
42
- let mut response = Response::new(BoxBody::new(Empty::new()));
41
+ let mut response = Response::new(HttpBody::empty());
43
42
  *response.status_mut() = self.redirect_type.status_code();
44
43
  let destination = self.to.rewrite_request(req, context).parse().map_err(|e| {
45
44
  magnus::Error::new(
@@ -134,8 +134,7 @@ impl MiddlewareLayer for StaticAssets {
134
134
  let file_server = self.file_server.get().unwrap();
135
135
  let encodings: &[HeaderValue] = context
136
136
  .supported_encoding_set()
137
- .map(Vec::as_slice)
138
- .unwrap_or(&[] as &[HeaderValue]);
137
+ .map_or(&[], |set| set.as_slice());
139
138
  let response = file_server
140
139
  .serve(
141
140
  &req,
@@ -1,15 +1,13 @@
1
1
  use std::sync::OnceLock;
2
2
 
3
3
  use super::{FromValue, MiddlewareLayer};
4
- use crate::server::http_message_types::{HttpRequest, HttpResponse};
4
+ use crate::server::http_message_types::{HttpBody, HttpRequest, HttpResponse};
5
5
  use crate::services::itsi_http_service::HttpRequestContext;
6
6
  use async_trait::async_trait;
7
7
  use bytes::Bytes;
8
8
  use derive_more::Debug;
9
9
  use either::Either;
10
10
  use http::{HeaderMap, HeaderName, HeaderValue, Response, StatusCode};
11
- use http_body_util::combinators::BoxBody;
12
- use http_body_util::Full;
13
11
  use itsi_error::ItsiError;
14
12
  use magnus::error::Result;
15
13
  use serde::Deserialize;
@@ -22,7 +20,7 @@ pub struct StaticResponse {
22
20
  #[serde(skip)]
23
21
  header_map: OnceLock<HeaderMap>,
24
22
  #[serde(skip)]
25
- body_bytes: OnceLock<Full<Bytes>>,
23
+ body_bytes: OnceLock<Bytes>,
26
24
  #[serde(skip)]
27
25
  status_code: OnceLock<StatusCode>,
28
26
  }
@@ -40,7 +38,7 @@ impl MiddlewareLayer for StaticResponse {
40
38
  .set(header_map)
41
39
  .map_err(|_| ItsiError::new("Failed to set headers"))?;
42
40
  self.body_bytes
43
- .set(Full::new(Bytes::from(self.body.clone())))
41
+ .set(Bytes::from(self.body.clone()))
44
42
  .map_err(|_| ItsiError::new("Failed to set body bytes"))?;
45
43
  self.status_code
46
44
  .set(StatusCode::from_u16(self.code).unwrap_or(StatusCode::OK))
@@ -53,7 +51,7 @@ impl MiddlewareLayer for StaticResponse {
53
51
  _req: HttpRequest,
54
52
  _context: &mut HttpRequestContext,
55
53
  ) -> Result<Either<HttpRequest, HttpResponse>> {
56
- let mut resp = Response::new(BoxBody::new(self.body_bytes.get().unwrap().clone()));
54
+ let mut resp = Response::new(HttpBody::full(self.body_bytes.get().unwrap().clone()));
57
55
  *resp.status_mut() = *self.status_code.get().unwrap();
58
56
  *resp.headers_mut() = self.header_map.get().unwrap().clone();
59
57
 
@@ -1,5 +1,6 @@
1
1
  pub mod binds;
2
2
  pub mod byte_frame;
3
+ pub mod frame_stream;
3
4
  pub mod http_message_types;
4
5
  pub mod io_stream;
5
6
  pub mod lifecycle_event;
@@ -79,7 +79,7 @@ impl ProcessWorker {
79
79
  ) {
80
80
  error!("Failed to set process group ID: {}", e);
81
81
  }
82
- match SingleMode::new(cluster_template.server_config.clone()) {
82
+ match SingleMode::new(cluster_template.server_config.clone(), self.worker_id) {
83
83
  Ok(single_mode) => {
84
84
  if cluster_template
85
85
  .server_config
@@ -88,7 +88,7 @@ impl ProcessWorker {
88
88
  .pin_worker_cores
89
89
  {
90
90
  core_affinity::set_for_current(
91
- CORE_IDS[self.worker_id % CORE_IDS.len()],
91
+ CORE_IDS[(2 * self.worker_id) % CORE_IDS.len()],
92
92
  );
93
93
  }
94
94
  Arc::new(single_mode).run().ok();
@@ -166,7 +166,7 @@ impl ProcessWorker {
166
166
  }
167
167
 
168
168
  pub(crate) fn boot_if_dead(&self, cluster_template: Arc<ClusterMode>) -> bool {
169
- if !self.is_alive() {
169
+ if !self.is_alive() && self.child_pid.lock().is_some() {
170
170
  if self.just_started() {
171
171
  error!(
172
172
  "Worker in crash loop {:?}. Refusing to restart",
@@ -202,7 +202,6 @@ impl ProcessWorker {
202
202
  let child_pid = *self.child_pid.lock();
203
203
  if let Some(pid) = child_pid {
204
204
  if self.is_alive() {
205
- info!("Worker still alive, sending SIGKILL {}", pid);
206
205
  if let Err(e) = kill(pid, SIGKILL) {
207
206
  error!("Failed to force kill process {}: {}", pid, e);
208
207
  }
@@ -1,6 +1,5 @@
1
- use std::{ops::Deref, pin::Pin, sync::Arc, time::Duration};
2
-
3
1
  use hyper_util::rt::TokioIo;
2
+ use std::{ops::Deref, pin::Pin, sync::Arc, time::Duration};
4
3
  use tokio::task::JoinSet;
5
4
  use tracing::debug;
6
5
 
@@ -40,17 +39,21 @@ impl Acceptor {
40
39
  let io: TokioIo<Pin<Box<IoStream>>> = TokioIo::new(Box::pin(stream));
41
40
  let mut shutdown_channel = self.shutdown_receiver.clone();
42
41
  let acceptor_args = self.acceptor_args.clone();
42
+ let service = ItsiHttpService {
43
+ inner: Arc::new(ItsiHttpServiceInner {
44
+ acceptor_args: acceptor_args.clone(),
45
+ addr,
46
+ }),
47
+ };
48
+
43
49
  self.join_set.spawn(async move {
44
50
  let executor = &acceptor_args.strategy.executor;
45
- let mut serve = Box::pin(executor.serve_connection_with_upgrades(
46
- io,
47
- ItsiHttpService {
48
- inner: Arc::new(ItsiHttpServiceInner {
49
- acceptor_args: acceptor_args.clone(),
50
- addr: addr.to_string(),
51
- }),
52
- },
53
- ));
51
+ let svc = hyper::service::service_fn(move |req| {
52
+ let service = service.clone();
53
+ async move { service.handle_request(req).await }
54
+ });
55
+
56
+ let mut serve = Box::pin(executor.serve_connection_with_upgrades(io, svc));
54
57
 
55
58
  tokio::select! {
56
59
  // Await the connection finishing naturally.
@@ -63,7 +66,6 @@ impl Acceptor {
63
66
  debug!("Connection closed abruptly: {:?}", res);
64
67
  }
65
68
  }
66
- serve.as_mut().graceful_shutdown();
67
69
  },
68
70
  // A lifecycle event triggers shutdown.
69
71
  _ = shutdown_channel.changed() => {
@@ -81,6 +83,7 @@ impl Acceptor {
81
83
 
82
84
  pub async fn join(&mut self) {
83
85
  // Join all acceptor tasks with timeout
86
+
84
87
  let deadline = tokio::time::Instant::now()
85
88
  + Duration::from_secs_f64(self.server_params.shutdown_timeout);
86
89
  let sleep_until = tokio::time::sleep_until(deadline);
@@ -89,6 +92,7 @@ impl Acceptor {
89
92
  while (self.join_set.join_next().await).is_some() {}
90
93
  } => {},
91
94
  _ = sleep_until => {
95
+ self.join_set.abort_all();
92
96
  debug!("Shutdown timeout reached; abandoning remaining acceptor tasks.");
93
97
  }
94
98
  }