spikard 0.3.5 → 0.3.6

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +659 -659
  4. data/ext/spikard_rb/Cargo.toml +17 -17
  5. data/ext/spikard_rb/extconf.rb +10 -10
  6. data/ext/spikard_rb/src/lib.rs +6 -6
  7. data/lib/spikard/app.rb +386 -386
  8. data/lib/spikard/background.rb +27 -27
  9. data/lib/spikard/config.rb +396 -396
  10. data/lib/spikard/converters.rb +13 -13
  11. data/lib/spikard/handler_wrapper.rb +113 -113
  12. data/lib/spikard/provide.rb +214 -214
  13. data/lib/spikard/response.rb +173 -173
  14. data/lib/spikard/schema.rb +243 -243
  15. data/lib/spikard/sse.rb +111 -111
  16. data/lib/spikard/streaming_response.rb +44 -44
  17. data/lib/spikard/testing.rb +221 -221
  18. data/lib/spikard/upload_file.rb +131 -131
  19. data/lib/spikard/version.rb +5 -5
  20. data/lib/spikard/websocket.rb +59 -59
  21. data/lib/spikard.rb +43 -43
  22. data/sig/spikard.rbs +366 -360
  23. data/vendor/crates/spikard-core/Cargo.toml +40 -40
  24. data/vendor/crates/spikard-core/src/bindings/mod.rs +3 -3
  25. data/vendor/crates/spikard-core/src/bindings/response.rs +133 -133
  26. data/vendor/crates/spikard-core/src/debug.rs +63 -63
  27. data/vendor/crates/spikard-core/src/di/container.rs +726 -726
  28. data/vendor/crates/spikard-core/src/di/dependency.rs +273 -273
  29. data/vendor/crates/spikard-core/src/di/error.rs +118 -118
  30. data/vendor/crates/spikard-core/src/di/factory.rs +538 -538
  31. data/vendor/crates/spikard-core/src/di/graph.rs +545 -545
  32. data/vendor/crates/spikard-core/src/di/mod.rs +192 -192
  33. data/vendor/crates/spikard-core/src/di/resolved.rs +411 -411
  34. data/vendor/crates/spikard-core/src/di/value.rs +283 -283
  35. data/vendor/crates/spikard-core/src/errors.rs +39 -39
  36. data/vendor/crates/spikard-core/src/http.rs +153 -153
  37. data/vendor/crates/spikard-core/src/lib.rs +29 -29
  38. data/vendor/crates/spikard-core/src/lifecycle.rs +422 -422
  39. data/vendor/crates/spikard-core/src/parameters.rs +722 -722
  40. data/vendor/crates/spikard-core/src/problem.rs +310 -310
  41. data/vendor/crates/spikard-core/src/request_data.rs +189 -189
  42. data/vendor/crates/spikard-core/src/router.rs +249 -249
  43. data/vendor/crates/spikard-core/src/schema_registry.rs +183 -183
  44. data/vendor/crates/spikard-core/src/type_hints.rs +304 -304
  45. data/vendor/crates/spikard-core/src/validation.rs +699 -699
  46. data/vendor/crates/spikard-http/Cargo.toml +68 -68
  47. data/vendor/crates/spikard-http/src/auth.rs +247 -247
  48. data/vendor/crates/spikard-http/src/background.rs +249 -249
  49. data/vendor/crates/spikard-http/src/bindings/mod.rs +3 -3
  50. data/vendor/crates/spikard-http/src/bindings/response.rs +1 -1
  51. data/vendor/crates/spikard-http/src/body_metadata.rs +8 -8
  52. data/vendor/crates/spikard-http/src/cors.rs +490 -490
  53. data/vendor/crates/spikard-http/src/debug.rs +63 -63
  54. data/vendor/crates/spikard-http/src/di_handler.rs +423 -423
  55. data/vendor/crates/spikard-http/src/handler_response.rs +190 -190
  56. data/vendor/crates/spikard-http/src/handler_trait.rs +228 -228
  57. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +284 -284
  58. data/vendor/crates/spikard-http/src/lib.rs +529 -529
  59. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +149 -149
  60. data/vendor/crates/spikard-http/src/lifecycle.rs +428 -428
  61. data/vendor/crates/spikard-http/src/middleware/mod.rs +285 -285
  62. data/vendor/crates/spikard-http/src/middleware/multipart.rs +86 -86
  63. data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +147 -147
  64. data/vendor/crates/spikard-http/src/middleware/validation.rs +287 -287
  65. data/vendor/crates/spikard-http/src/openapi/mod.rs +309 -309
  66. data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +190 -190
  67. data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +308 -308
  68. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +195 -195
  69. data/vendor/crates/spikard-http/src/parameters.rs +1 -1
  70. data/vendor/crates/spikard-http/src/problem.rs +1 -1
  71. data/vendor/crates/spikard-http/src/query_parser.rs +369 -369
  72. data/vendor/crates/spikard-http/src/response.rs +399 -399
  73. data/vendor/crates/spikard-http/src/router.rs +1 -1
  74. data/vendor/crates/spikard-http/src/schema_registry.rs +1 -1
  75. data/vendor/crates/spikard-http/src/server/handler.rs +87 -87
  76. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +98 -98
  77. data/vendor/crates/spikard-http/src/server/mod.rs +805 -805
  78. data/vendor/crates/spikard-http/src/server/request_extraction.rs +119 -119
  79. data/vendor/crates/spikard-http/src/sse.rs +447 -447
  80. data/vendor/crates/spikard-http/src/testing/form.rs +14 -14
  81. data/vendor/crates/spikard-http/src/testing/multipart.rs +60 -60
  82. data/vendor/crates/spikard-http/src/testing/test_client.rs +285 -285
  83. data/vendor/crates/spikard-http/src/testing.rs +377 -377
  84. data/vendor/crates/spikard-http/src/type_hints.rs +1 -1
  85. data/vendor/crates/spikard-http/src/validation.rs +1 -1
  86. data/vendor/crates/spikard-http/src/websocket.rs +324 -324
  87. data/vendor/crates/spikard-rb/Cargo.toml +42 -42
  88. data/vendor/crates/spikard-rb/build.rs +8 -8
  89. data/vendor/crates/spikard-rb/src/background.rs +63 -63
  90. data/vendor/crates/spikard-rb/src/config.rs +294 -294
  91. data/vendor/crates/spikard-rb/src/conversion.rs +453 -453
  92. data/vendor/crates/spikard-rb/src/di.rs +409 -409
  93. data/vendor/crates/spikard-rb/src/handler.rs +625 -625
  94. data/vendor/crates/spikard-rb/src/lib.rs +2771 -2771
  95. data/vendor/crates/spikard-rb/src/lifecycle.rs +274 -274
  96. data/vendor/crates/spikard-rb/src/server.rs +283 -283
  97. data/vendor/crates/spikard-rb/src/sse.rs +231 -231
  98. data/vendor/crates/spikard-rb/src/test_client.rs +404 -404
  99. data/vendor/crates/spikard-rb/src/test_sse.rs +143 -143
  100. data/vendor/crates/spikard-rb/src/test_websocket.rs +221 -221
  101. data/vendor/crates/spikard-rb/src/websocket.rs +233 -233
  102. metadata +1 -1
@@ -1,249 +1,249 @@
1
- use std::borrow::Cow;
2
- use std::sync::Arc;
3
- use std::time::Duration;
4
-
5
- use futures::FutureExt;
6
- use futures::future::BoxFuture;
7
- use tokio::sync::{Semaphore, mpsc};
8
- use tokio::task::JoinSet;
9
- use tokio::time::timeout;
10
- use tokio_util::sync::CancellationToken;
11
-
12
- /// Configuration for in-process background task execution.
13
- #[derive(Clone, Debug)]
14
- pub struct BackgroundTaskConfig {
15
- pub max_queue_size: usize,
16
- pub max_concurrent_tasks: usize,
17
- pub drain_timeout_secs: u64,
18
- }
19
-
20
- impl Default for BackgroundTaskConfig {
21
- fn default() -> Self {
22
- Self {
23
- max_queue_size: 1024,
24
- max_concurrent_tasks: 128,
25
- drain_timeout_secs: 30,
26
- }
27
- }
28
- }
29
-
30
- #[derive(Clone, Debug)]
31
- pub struct BackgroundJobMetadata {
32
- pub name: Cow<'static, str>,
33
- pub request_id: Option<String>,
34
- }
35
-
36
- impl Default for BackgroundJobMetadata {
37
- fn default() -> Self {
38
- Self {
39
- name: Cow::Borrowed("background_task"),
40
- request_id: None,
41
- }
42
- }
43
- }
44
-
45
- pub type BackgroundJobFuture = BoxFuture<'static, Result<(), BackgroundJobError>>;
46
-
47
- struct BackgroundJob {
48
- pub future: BackgroundJobFuture,
49
- pub metadata: BackgroundJobMetadata,
50
- }
51
-
52
- impl BackgroundJob {
53
- fn new<F>(future: F, metadata: BackgroundJobMetadata) -> Self
54
- where
55
- F: futures::Future<Output = Result<(), BackgroundJobError>> + Send + 'static,
56
- {
57
- Self {
58
- future: future.boxed(),
59
- metadata,
60
- }
61
- }
62
- }
63
-
64
- #[derive(Debug, Clone)]
65
- pub struct BackgroundJobError {
66
- pub message: String,
67
- }
68
-
69
- impl From<String> for BackgroundJobError {
70
- fn from(message: String) -> Self {
71
- Self { message }
72
- }
73
- }
74
-
75
- impl From<&str> for BackgroundJobError {
76
- fn from(message: &str) -> Self {
77
- Self {
78
- message: message.to_string(),
79
- }
80
- }
81
- }
82
-
83
- #[derive(Debug, Clone)]
84
- pub enum BackgroundSpawnError {
85
- QueueFull,
86
- }
87
-
88
- impl std::fmt::Display for BackgroundSpawnError {
89
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90
- match self {
91
- BackgroundSpawnError::QueueFull => write!(f, "background task queue is full"),
92
- }
93
- }
94
- }
95
-
96
- impl std::error::Error for BackgroundSpawnError {}
97
-
98
- #[derive(Debug)]
99
- pub struct BackgroundShutdownError;
100
-
101
- #[derive(Default)]
102
- struct BackgroundMetrics {
103
- queued: std::sync::atomic::AtomicU64,
104
- running: std::sync::atomic::AtomicU64,
105
- failed: std::sync::atomic::AtomicU64,
106
- }
107
-
108
- impl BackgroundMetrics {
109
- fn inc_queued(&self) {
110
- self.queued.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
111
- }
112
-
113
- fn dec_queued(&self) {
114
- self.queued.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
115
- }
116
-
117
- fn inc_running(&self) {
118
- self.running.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
119
- }
120
-
121
- fn dec_running(&self) {
122
- self.running.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
123
- }
124
-
125
- fn inc_failed(&self) {
126
- self.failed.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
127
- }
128
- }
129
-
130
- #[derive(Clone)]
131
- pub struct BackgroundHandle {
132
- sender: mpsc::Sender<BackgroundJob>,
133
- metrics: Arc<BackgroundMetrics>,
134
- }
135
-
136
- impl BackgroundHandle {
137
- pub fn spawn<F, Fut>(&self, f: F) -> Result<(), BackgroundSpawnError>
138
- where
139
- F: FnOnce() -> Fut,
140
- Fut: futures::Future<Output = Result<(), BackgroundJobError>> + Send + 'static,
141
- {
142
- let future = f();
143
- self.spawn_with_metadata(future, BackgroundJobMetadata::default())
144
- }
145
-
146
- pub fn spawn_with_metadata<Fut>(
147
- &self,
148
- future: Fut,
149
- metadata: BackgroundJobMetadata,
150
- ) -> Result<(), BackgroundSpawnError>
151
- where
152
- Fut: futures::Future<Output = Result<(), BackgroundJobError>> + Send + 'static,
153
- {
154
- self.metrics.inc_queued();
155
- let job = BackgroundJob::new(future, metadata);
156
- self.sender.try_send(job).map_err(|_| {
157
- self.metrics.dec_queued();
158
- BackgroundSpawnError::QueueFull
159
- })
160
- }
161
- }
162
-
163
- pub struct BackgroundRuntime {
164
- handle: BackgroundHandle,
165
- drain_timeout: Duration,
166
- shutdown_token: CancellationToken,
167
- join_handle: tokio::task::JoinHandle<()>,
168
- }
169
-
170
- impl BackgroundRuntime {
171
- pub async fn start(config: BackgroundTaskConfig) -> Self {
172
- let (tx, rx) = mpsc::channel(config.max_queue_size);
173
- let metrics = Arc::new(BackgroundMetrics::default());
174
- let handle = BackgroundHandle {
175
- sender: tx.clone(),
176
- metrics: metrics.clone(),
177
- };
178
- let shutdown_token = CancellationToken::new();
179
- let semaphore = Arc::new(Semaphore::new(config.max_concurrent_tasks));
180
- let driver_token = shutdown_token.clone();
181
-
182
- let join_handle = tokio::spawn(run_executor(rx, semaphore, metrics.clone(), driver_token));
183
-
184
- Self {
185
- handle,
186
- drain_timeout: Duration::from_secs(config.drain_timeout_secs),
187
- shutdown_token,
188
- join_handle,
189
- }
190
- }
191
-
192
- pub fn handle(&self) -> BackgroundHandle {
193
- self.handle.clone()
194
- }
195
-
196
- pub async fn shutdown(self) -> Result<(), BackgroundShutdownError> {
197
- self.shutdown_token.cancel();
198
- drop(self.handle);
199
- match timeout(self.drain_timeout, self.join_handle).await {
200
- Ok(Ok(_)) => Ok(()),
201
- _ => Err(BackgroundShutdownError),
202
- }
203
- }
204
- }
205
-
206
- async fn run_executor(
207
- mut rx: mpsc::Receiver<BackgroundJob>,
208
- semaphore: Arc<Semaphore>,
209
- metrics: Arc<BackgroundMetrics>,
210
- token: CancellationToken,
211
- ) {
212
- let mut join_set = JoinSet::new();
213
-
214
- loop {
215
- tokio::select! {
216
- _ = token.cancelled() => {
217
- break;
218
- }
219
- maybe_job = rx.recv() => {
220
- match maybe_job {
221
- Some(job) => {
222
- metrics.dec_queued();
223
- let semaphore = semaphore.clone();
224
- let metrics_clone = metrics.clone();
225
- join_set.spawn(async move {
226
- let BackgroundJob { future, metadata } = job;
227
- match semaphore.acquire_owned().await {
228
- Ok(_permit) => {
229
- metrics_clone.inc_running();
230
- if let Err(err) = future.await {
231
- metrics_clone.inc_failed();
232
- tracing::error!(target = "spikard::background", task = %metadata.name, error = %err.message, "background task failed");
233
- }
234
- metrics_clone.dec_running();
235
- }
236
- Err(_) => {
237
- tracing::warn!(target = "spikard::background", "failed to acquire semaphore permit for background task");
238
- }
239
- }
240
- });
241
- }
242
- None => break,
243
- }
244
- }
245
- }
246
- }
247
-
248
- while join_set.join_next().await.is_some() {}
249
- }
1
+ use std::borrow::Cow;
2
+ use std::sync::Arc;
3
+ use std::time::Duration;
4
+
5
+ use futures::FutureExt;
6
+ use futures::future::BoxFuture;
7
+ use tokio::sync::{Semaphore, mpsc};
8
+ use tokio::task::JoinSet;
9
+ use tokio::time::timeout;
10
+ use tokio_util::sync::CancellationToken;
11
+
12
+ /// Configuration for in-process background task execution.
13
+ #[derive(Clone, Debug)]
14
+ pub struct BackgroundTaskConfig {
15
+ pub max_queue_size: usize,
16
+ pub max_concurrent_tasks: usize,
17
+ pub drain_timeout_secs: u64,
18
+ }
19
+
20
+ impl Default for BackgroundTaskConfig {
21
+ fn default() -> Self {
22
+ Self {
23
+ max_queue_size: 1024,
24
+ max_concurrent_tasks: 128,
25
+ drain_timeout_secs: 30,
26
+ }
27
+ }
28
+ }
29
+
30
+ #[derive(Clone, Debug)]
31
+ pub struct BackgroundJobMetadata {
32
+ pub name: Cow<'static, str>,
33
+ pub request_id: Option<String>,
34
+ }
35
+
36
+ impl Default for BackgroundJobMetadata {
37
+ fn default() -> Self {
38
+ Self {
39
+ name: Cow::Borrowed("background_task"),
40
+ request_id: None,
41
+ }
42
+ }
43
+ }
44
+
45
+ pub type BackgroundJobFuture = BoxFuture<'static, Result<(), BackgroundJobError>>;
46
+
47
+ struct BackgroundJob {
48
+ pub future: BackgroundJobFuture,
49
+ pub metadata: BackgroundJobMetadata,
50
+ }
51
+
52
+ impl BackgroundJob {
53
+ fn new<F>(future: F, metadata: BackgroundJobMetadata) -> Self
54
+ where
55
+ F: futures::Future<Output = Result<(), BackgroundJobError>> + Send + 'static,
56
+ {
57
+ Self {
58
+ future: future.boxed(),
59
+ metadata,
60
+ }
61
+ }
62
+ }
63
+
64
+ #[derive(Debug, Clone)]
65
+ pub struct BackgroundJobError {
66
+ pub message: String,
67
+ }
68
+
69
+ impl From<String> for BackgroundJobError {
70
+ fn from(message: String) -> Self {
71
+ Self { message }
72
+ }
73
+ }
74
+
75
+ impl From<&str> for BackgroundJobError {
76
+ fn from(message: &str) -> Self {
77
+ Self {
78
+ message: message.to_string(),
79
+ }
80
+ }
81
+ }
82
+
83
+ #[derive(Debug, Clone)]
84
+ pub enum BackgroundSpawnError {
85
+ QueueFull,
86
+ }
87
+
88
+ impl std::fmt::Display for BackgroundSpawnError {
89
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90
+ match self {
91
+ BackgroundSpawnError::QueueFull => write!(f, "background task queue is full"),
92
+ }
93
+ }
94
+ }
95
+
96
+ impl std::error::Error for BackgroundSpawnError {}
97
+
98
+ #[derive(Debug)]
99
+ pub struct BackgroundShutdownError;
100
+
101
+ #[derive(Default)]
102
+ struct BackgroundMetrics {
103
+ queued: std::sync::atomic::AtomicU64,
104
+ running: std::sync::atomic::AtomicU64,
105
+ failed: std::sync::atomic::AtomicU64,
106
+ }
107
+
108
+ impl BackgroundMetrics {
109
+ fn inc_queued(&self) {
110
+ self.queued.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
111
+ }
112
+
113
+ fn dec_queued(&self) {
114
+ self.queued.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
115
+ }
116
+
117
+ fn inc_running(&self) {
118
+ self.running.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
119
+ }
120
+
121
+ fn dec_running(&self) {
122
+ self.running.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
123
+ }
124
+
125
+ fn inc_failed(&self) {
126
+ self.failed.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
127
+ }
128
+ }
129
+
130
+ #[derive(Clone)]
131
+ pub struct BackgroundHandle {
132
+ sender: mpsc::Sender<BackgroundJob>,
133
+ metrics: Arc<BackgroundMetrics>,
134
+ }
135
+
136
+ impl BackgroundHandle {
137
+ pub fn spawn<F, Fut>(&self, f: F) -> Result<(), BackgroundSpawnError>
138
+ where
139
+ F: FnOnce() -> Fut,
140
+ Fut: futures::Future<Output = Result<(), BackgroundJobError>> + Send + 'static,
141
+ {
142
+ let future = f();
143
+ self.spawn_with_metadata(future, BackgroundJobMetadata::default())
144
+ }
145
+
146
+ pub fn spawn_with_metadata<Fut>(
147
+ &self,
148
+ future: Fut,
149
+ metadata: BackgroundJobMetadata,
150
+ ) -> Result<(), BackgroundSpawnError>
151
+ where
152
+ Fut: futures::Future<Output = Result<(), BackgroundJobError>> + Send + 'static,
153
+ {
154
+ self.metrics.inc_queued();
155
+ let job = BackgroundJob::new(future, metadata);
156
+ self.sender.try_send(job).map_err(|_| {
157
+ self.metrics.dec_queued();
158
+ BackgroundSpawnError::QueueFull
159
+ })
160
+ }
161
+ }
162
+
163
+ pub struct BackgroundRuntime {
164
+ handle: BackgroundHandle,
165
+ drain_timeout: Duration,
166
+ shutdown_token: CancellationToken,
167
+ join_handle: tokio::task::JoinHandle<()>,
168
+ }
169
+
170
+ impl BackgroundRuntime {
171
+ pub async fn start(config: BackgroundTaskConfig) -> Self {
172
+ let (tx, rx) = mpsc::channel(config.max_queue_size);
173
+ let metrics = Arc::new(BackgroundMetrics::default());
174
+ let handle = BackgroundHandle {
175
+ sender: tx.clone(),
176
+ metrics: metrics.clone(),
177
+ };
178
+ let shutdown_token = CancellationToken::new();
179
+ let semaphore = Arc::new(Semaphore::new(config.max_concurrent_tasks));
180
+ let driver_token = shutdown_token.clone();
181
+
182
+ let join_handle = tokio::spawn(run_executor(rx, semaphore, metrics.clone(), driver_token));
183
+
184
+ Self {
185
+ handle,
186
+ drain_timeout: Duration::from_secs(config.drain_timeout_secs),
187
+ shutdown_token,
188
+ join_handle,
189
+ }
190
+ }
191
+
192
+ pub fn handle(&self) -> BackgroundHandle {
193
+ self.handle.clone()
194
+ }
195
+
196
+ pub async fn shutdown(self) -> Result<(), BackgroundShutdownError> {
197
+ self.shutdown_token.cancel();
198
+ drop(self.handle);
199
+ match timeout(self.drain_timeout, self.join_handle).await {
200
+ Ok(Ok(_)) => Ok(()),
201
+ _ => Err(BackgroundShutdownError),
202
+ }
203
+ }
204
+ }
205
+
206
+ async fn run_executor(
207
+ mut rx: mpsc::Receiver<BackgroundJob>,
208
+ semaphore: Arc<Semaphore>,
209
+ metrics: Arc<BackgroundMetrics>,
210
+ token: CancellationToken,
211
+ ) {
212
+ let mut join_set = JoinSet::new();
213
+
214
+ loop {
215
+ tokio::select! {
216
+ _ = token.cancelled() => {
217
+ break;
218
+ }
219
+ maybe_job = rx.recv() => {
220
+ match maybe_job {
221
+ Some(job) => {
222
+ metrics.dec_queued();
223
+ let semaphore = semaphore.clone();
224
+ let metrics_clone = metrics.clone();
225
+ join_set.spawn(async move {
226
+ let BackgroundJob { future, metadata } = job;
227
+ match semaphore.acquire_owned().await {
228
+ Ok(_permit) => {
229
+ metrics_clone.inc_running();
230
+ if let Err(err) = future.await {
231
+ metrics_clone.inc_failed();
232
+ tracing::error!(target = "spikard::background", task = %metadata.name, error = %err.message, "background task failed");
233
+ }
234
+ metrics_clone.dec_running();
235
+ }
236
+ Err(_) => {
237
+ tracing::warn!(target = "spikard::background", "failed to acquire semaphore permit for background task");
238
+ }
239
+ }
240
+ });
241
+ }
242
+ None => break,
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ while join_set.join_next().await.is_some() {}
249
+ }
@@ -1,3 +1,3 @@
1
- pub mod response;
2
-
3
- pub use response::{RawResponse, StaticAsset};
1
+ pub mod response;
2
+
3
+ pub use response::{RawResponse, StaticAsset};
@@ -1 +1 @@
1
- pub use spikard_core::bindings::response::*;
1
+ pub use spikard_core::bindings::response::*;
@@ -1,8 +1,8 @@
1
- //! Shared metadata stored on `http::Response` extensions.
2
-
3
- /// Extension type storing the original, uncompressed response body size in bytes.
4
- ///
5
- /// Middleware (like compression) can inspect this to make deterministic decisions
6
- /// even when the final body length would otherwise require buffering.
7
- #[derive(Debug, Clone, Copy)]
8
- pub struct ResponseBodySize(pub usize);
1
+ //! Shared metadata stored on `http::Response` extensions.
2
+
3
+ /// Extension type storing the original, uncompressed response body size in bytes.
4
+ ///
5
+ /// Middleware (like compression) can inspect this to make deterministic decisions
6
+ /// even when the final body length would otherwise require buffering.
7
+ #[derive(Debug, Clone, Copy)]
8
+ pub struct ResponseBodySize(pub usize);