Skip to content

Commit deffeef

Browse files
committed
0.2.19. Shutdown and documentation fixes. Force bindgen to include stdbool and c99 to fix arch build issues.
1 parent d72d15d commit deffeef

File tree

10 files changed

+73
-37
lines changed

10 files changed

+73
-37
lines changed

CHANGELOG.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
## [0.2.18] - 2025-XX-XX
2-
### WIP
3-
-- Fixing error in auto-reload on Linux when reuse_port is false
4-
-- Fix breaking of auto-reload on config file errors
5-
-- include directive is relative (equivalent to require_relative)
6-
-- Fixing preload gem group logic
7-
-- Fix errors in interrupt handling during some debug flows
1+
## [0.2.19] - 2025-08-09
2+
- Fixed shutdown hook incorrectly being skipped
3+
- Documentation fixes
4+
- Fixed stuck graceful shutdown scenario
5+
6+
## [0.2.18] - 2025-06-20
7+
- Fixing error in auto-reload on Linux when reuse_port is false
8+
- Fix breaking of auto-reload on config file errors
9+
- include directive is relative (equivalent to require_relative)
10+
- Fixing preload gem group logic
11+
- Fix errors in interrupt handling during some debug flows
812

913
## [0.2.17] - 2025-05-31
1014
- Enabled vectorized writes in IoSteam

Gemfile.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
PATH
22
remote: .
33
specs:
4-
itsi (0.2.18)
5-
itsi-scheduler (~> 0.2.18)
6-
itsi-server (~> 0.2.18)
4+
itsi (0.2.19)
5+
itsi-scheduler (~> 0.2.19)
6+
itsi-server (~> 0.2.19)
77

88
PATH
99
remote: gems/scheduler
1010
specs:
11-
itsi-scheduler (0.2.18)
11+
itsi-scheduler (0.2.19)
1212
rb_sys (~> 0.9.91)
1313

1414
PATH
1515
remote: gems/server
1616
specs:
17-
itsi-server (0.2.18)
17+
itsi-server (0.2.19)
1818
json (~> 2)
1919
prism (~> 1.4)
2020
rack (>= 1.6)

crates/itsi_scheduler/extconf.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# frozen_string_literal: true
22

3-
require "mkmf"
4-
require "rb_sys/mkmf"
3+
require 'mkmf'
4+
require 'rb_sys/mkmf'
55

6-
create_rust_makefile("itsi/scheduler/itsi_scheduler") do |r|
7-
r.extra_rustflags = ["-C target-cpu=native"]
6+
create_rust_makefile('itsi/scheduler/itsi_scheduler') do |r|
7+
r.extra_rustflags = ['-C target-cpu=native']
8+
r.env = {
9+
'BINDGEN_EXTRA_CLANG_ARGS' => '-include stdbool.h -std=c99'
10+
}
811
end

crates/itsi_server/extconf.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# frozen_string_literal: true
22

3-
require "mkmf"
4-
require "rb_sys/mkmf"
3+
require 'mkmf'
4+
require 'rb_sys/mkmf'
55

6-
create_rust_makefile("itsi/server/itsi_server") do |r|
7-
r.extra_rustflags = ["-C target-cpu=native"]
6+
create_rust_makefile('itsi/server/itsi_server') do |r|
7+
r.extra_rustflags = ['-C target-cpu=native']
8+
r.env = {
9+
'BINDGEN_EXTRA_CLANG_ARGS' => '-include stdbool.h -std=c99'
10+
}
811
end

crates/itsi_server/src/server/serve_strategy/cluster_mode.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,13 @@ impl ClusterMode {
377377
}
378378
lifecycle_event = lifecycle_rx.recv() => match lifecycle_event{
379379
Ok(lifecycle_event) => {
380+
debug!("Cluster mode received lifecycle event: {:?}", lifecycle_event);
380381
if let Err(e) = self_ref.clone().handle_lifecycle_event(lifecycle_event).await{
381382
match e {
382-
ItsiError::Break => break,
383+
ItsiError::Break => {
384+
debug!("Lifecycle event triggered shutdown, breaking cluster monitor loop");
385+
break;
386+
},
383387
_ => error!("Error in handle_lifecycle_event {:?}", e)
384388
}
385389
}

crates/itsi_server/src/server/signal.rs

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use std::{
22
collections::VecDeque,
3-
sync::atomic::{AtomicBool, AtomicI8},
3+
sync::atomic::{AtomicBool, AtomicI8, Ordering},
44
};
55

66
use nix::libc::{self, sighandler_t};
77
use parking_lot::Mutex;
88
use tokio::sync::broadcast;
9+
use tracing::{debug, warn};
910

1011
use super::lifecycle_event::LifecycleEvent;
1112

@@ -21,12 +22,14 @@ pub fn subscribe_runtime_to_signals() -> broadcast::Receiver<LifecycleEvent> {
2122
if let Some(sender) = guard.as_ref() {
2223
return sender.subscribe();
2324
}
24-
let (sender, receiver) = broadcast::channel(5);
25+
let (sender, receiver) = broadcast::channel(32);
2526
let sender_clone = sender.clone();
2627
std::thread::spawn(move || {
27-
std::thread::sleep(std::time::Duration::from_millis(50));
28+
std::thread::sleep(std::time::Duration::from_millis(10));
2829
for event in PENDING_QUEUE.lock().drain(..) {
29-
sender_clone.send(event).ok();
30+
if let Err(e) = sender_clone.send(event) {
31+
eprintln!("Warning: Failed to send pending lifecycle event {:?}", e);
32+
}
3033
}
3134
});
3235

@@ -41,22 +44,36 @@ pub fn unsubscribe_runtime() {
4144

4245
pub fn send_lifecycle_event(event: LifecycleEvent) {
4346
if let Some(sender) = SIGNAL_HANDLER_CHANNEL.lock().as_ref() {
44-
sender.send(event).ok();
47+
if let Err(e) = sender.send(event) {
48+
// Channel full or receivers dropped - this is a critical error for shutdown signals
49+
eprintln!("Critical: Failed to send lifecycle event {:?}", e);
50+
// For shutdown events, try to force exit if channel delivery fails
51+
if matches!(
52+
e.0,
53+
LifecycleEvent::Shutdown | LifecycleEvent::ForceShutdown
54+
) {
55+
eprintln!("Emergency shutdown due to signal delivery failure");
56+
std::process::exit(1);
57+
}
58+
}
4559
} else {
4660
PENDING_QUEUE.lock().push_back(event);
4761
}
4862
}
4963

5064
fn receive_signal(signum: i32, _: sighandler_t) {
51-
SIGINT_COUNT.fetch_add(-1, std::sync::atomic::Ordering::SeqCst);
65+
debug!("Received signal: {}", signum);
66+
SIGINT_COUNT.fetch_add(-1, Ordering::SeqCst);
5267
let event = match signum {
5368
libc::SIGTERM | libc::SIGINT => {
54-
SHUTDOWN_REQUESTED.store(true, std::sync::atomic::Ordering::SeqCst);
55-
SIGINT_COUNT.fetch_add(2, std::sync::atomic::Ordering::SeqCst);
56-
if SIGINT_COUNT.load(std::sync::atomic::Ordering::SeqCst) < 2 {
69+
debug!("Received shutdown signal (SIGTERM/SIGINT)");
70+
SHUTDOWN_REQUESTED.store(true, Ordering::SeqCst);
71+
SIGINT_COUNT.fetch_add(2, Ordering::SeqCst);
72+
if SIGINT_COUNT.load(Ordering::SeqCst) < 2 {
73+
debug!("First shutdown signal, requesting graceful shutdown");
5774
Some(LifecycleEvent::Shutdown)
5875
} else {
59-
// Not messing about. Force shutdown.
76+
warn!("Multiple shutdown signals received, forcing immediate shutdown");
6077
Some(LifecycleEvent::ForceShutdown)
6178
}
6279
}
@@ -70,13 +87,17 @@ fn receive_signal(signum: i32, _: sighandler_t) {
7087
};
7188

7289
if let Some(event) = event {
90+
debug!("Signal {} mapped to lifecycle event: {:?}", signum, event);
7391
send_lifecycle_event(event);
92+
} else {
93+
debug!("Signal {} not mapped to any lifecycle event", signum);
7494
}
7595
}
7696

7797
pub fn reset_signal_handlers() -> bool {
78-
SIGINT_COUNT.store(0, std::sync::atomic::Ordering::SeqCst);
79-
SHUTDOWN_REQUESTED.store(false, std::sync::atomic::Ordering::SeqCst);
98+
debug!("Resetting signal handlers");
99+
SIGINT_COUNT.store(0, Ordering::SeqCst);
100+
SHUTDOWN_REQUESTED.store(false, Ordering::SeqCst);
80101

81102
unsafe {
82103
libc::signal(libc::SIGTERM, receive_signal as usize);
@@ -92,6 +113,7 @@ pub fn reset_signal_handlers() -> bool {
92113
}
93114

94115
pub fn clear_signal_handlers() {
116+
debug!("Clearing signal handlers");
95117
unsafe {
96118
libc::signal(libc::SIGTERM, libc::SIG_DFL);
97119
libc::signal(libc::SIGINT, libc::SIG_DFL);

examples/api_with_schema_and_controllers/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Simple example of how you can use the following options:
33

44
* https://itsi.fyi/middleware/endpoint/
5-
* https://itsi.fyi/middleware/endpoint/controller
5+
* https://itsi.fyi/middleware/controller
66
* https://itsi.fyi/middleware/endpoint/schemas/
77

88
to create validated JSON endpoints directly inside Itsi without a dedicated framework

gems/scheduler/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gems/server/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gems/server/lib/itsi/server/config/middleware/rate_limit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ How to identify the client:
3939
```
4040
or
4141
```ruby
42-
key: { parameter: { query: { name: "user_id" } } }
42+
key: { parameter: { query: "user_id" } }
4343
```
4444

4545
### `store_config`

0 commit comments

Comments
 (0)