itsi 0.2.18 → 0.2.20

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d643690ccc0157ece254b12b72bd4eff904a907db970639df8567c43693b2c7b
4
- data.tar.gz: 5202c977ca30f83ddc09fc9bbe31966b06ffb5beda308568a684e0242d3898f7
3
+ metadata.gz: be6fb043079da062b69fdfbd7ecc1ec01bfdd7d02686f4461431de2a7a9f81dc
4
+ data.tar.gz: cb2d78ab71f2308f0211c2f89684257ee2827c9534fb9296d38cc46a779b127c
5
5
  SHA512:
6
- metadata.gz: 07567a207915ae2f6d4dc0c6827e5b9008574f1e8b9864b0969657a06d5f96f4d638b0532187da82511b7f71b06c7bc1499fd1cd32cb7e85fa13c3cb0d76e34a
7
- data.tar.gz: 0f7bfcc95d1a79deae127f6899122c8ffd3d3042332ad33bbc2cf0e490abb9392dfbce76f4cbcfa878b58ef8e6ee8b3694853994c9c78dbc2b4165fe76bf6be5
6
+ metadata.gz: 19006847757b090063a44d9230de44b998e2e070e5002db9a52744c5a1dc44c1c9267aa0783c2c76f98f30129e90874c0c6f2d0993a54288a1dcff832a693591
7
+ data.tar.gz: 3e2a583aceb46c8ffe415e451d38931dbc3ead6a846a9bd5c38fc6a9561e24308c37703c64c6db589f58841bd0c2acb0ee3586850293df822ce38583395f4e9b
data/CHANGELOG.md CHANGED
@@ -1,10 +1,17 @@
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.20] - 2025-09-01
2
+ - Ensured Itsi server can run within a read-only file-system
3
+
4
+ ## [0.2.19] - 2025-08-09
5
+ - Fixed shutdown hook incorrectly being skipped
6
+ - Documentation fixes
7
+ - Fixed stuck graceful shutdown scenario
8
+
9
+ ## [0.2.18] - 2025-06-20
10
+ - Fixing error in auto-reload on Linux when reuse_port is false
11
+ - Fix breaking of auto-reload on config file errors
12
+ - include directive is relative (equivalent to require_relative)
13
+ - Fixing preload gem group logic
14
+ - Fix errors in interrupt handling during some debug flows
8
15
 
9
16
  ## [0.2.17] - 2025-05-31
10
17
  - Enabled vectorized writes in IoSteam
data/Cargo.lock CHANGED
@@ -1644,7 +1644,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
1644
1644
 
1645
1645
  [[package]]
1646
1646
  name = "itsi-scheduler"
1647
- version = "0.2.18"
1647
+ version = "0.2.20"
1648
1648
  dependencies = [
1649
1649
  "bytes",
1650
1650
  "derive_more",
@@ -1662,7 +1662,7 @@ dependencies = [
1662
1662
 
1663
1663
  [[package]]
1664
1664
  name = "itsi-server"
1665
- version = "0.2.18"
1665
+ version = "0.2.20"
1666
1666
  dependencies = [
1667
1667
  "argon2",
1668
1668
  "async-channel",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "itsi-scheduler"
3
- version = "0.2.18"
3
+ version = "0.2.20"
4
4
  edition = "2021"
5
5
  authors = ["Wouter Coppieters <wc@pico.net.nz>"]
6
6
  license = "MIT"
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mkmf"
4
- require "rb_sys/mkmf"
3
+ require 'mkmf'
4
+ require 'rb_sys/mkmf'
5
5
 
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
+ }
8
11
  end
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "itsi-server"
3
- version = "0.2.18"
3
+ version = "0.2.20"
4
4
  edition = "2021"
5
5
  authors = ["Wouter Coppieters <wc@pico.net.nz>"]
6
6
  license = "MIT"
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mkmf"
4
- require "rb_sys/mkmf"
3
+ require 'mkmf'
4
+ require 'rb_sys/mkmf'
5
5
 
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
+ }
8
11
  end
@@ -377,9 +377,13 @@ impl ClusterMode {
377
377
  }
378
378
  lifecycle_event = lifecycle_rx.recv() => match lifecycle_event{
379
379
  Ok(lifecycle_event) => {
380
+ debug!("Cluster mode received lifecycle event: {:?}", lifecycle_event);
380
381
  if let Err(e) = self_ref.clone().handle_lifecycle_event(lifecycle_event).await{
381
382
  match e {
382
- ItsiError::Break => break,
383
+ ItsiError::Break => {
384
+ debug!("Lifecycle event triggered shutdown, breaking cluster monitor loop");
385
+ break;
386
+ },
383
387
  _ => error!("Error in handle_lifecycle_event {:?}", e)
384
388
  }
385
389
  }
@@ -1,11 +1,12 @@
1
1
  use std::{
2
2
  collections::VecDeque,
3
- sync::atomic::{AtomicBool, AtomicI8},
3
+ sync::atomic::{AtomicBool, AtomicI8, Ordering},
4
4
  };
5
5
 
6
6
  use nix::libc::{self, sighandler_t};
7
7
  use parking_lot::Mutex;
8
8
  use tokio::sync::broadcast;
9
+ use tracing::{debug, warn};
9
10
 
10
11
  use super::lifecycle_event::LifecycleEvent;
11
12
 
@@ -21,12 +22,14 @@ pub fn subscribe_runtime_to_signals() -> broadcast::Receiver<LifecycleEvent> {
21
22
  if let Some(sender) = guard.as_ref() {
22
23
  return sender.subscribe();
23
24
  }
24
- let (sender, receiver) = broadcast::channel(5);
25
+ let (sender, receiver) = broadcast::channel(32);
25
26
  let sender_clone = sender.clone();
26
27
  std::thread::spawn(move || {
27
- std::thread::sleep(std::time::Duration::from_millis(50));
28
+ std::thread::sleep(std::time::Duration::from_millis(10));
28
29
  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
+ }
30
33
  }
31
34
  });
32
35
 
@@ -41,22 +44,36 @@ pub fn unsubscribe_runtime() {
41
44
 
42
45
  pub fn send_lifecycle_event(event: LifecycleEvent) {
43
46
  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
+ }
45
59
  } else {
46
60
  PENDING_QUEUE.lock().push_back(event);
47
61
  }
48
62
  }
49
63
 
50
64
  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);
52
67
  let event = match signum {
53
68
  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");
57
74
  Some(LifecycleEvent::Shutdown)
58
75
  } else {
59
- // Not messing about. Force shutdown.
76
+ warn!("Multiple shutdown signals received, forcing immediate shutdown");
60
77
  Some(LifecycleEvent::ForceShutdown)
61
78
  }
62
79
  }
@@ -70,13 +87,17 @@ fn receive_signal(signum: i32, _: sighandler_t) {
70
87
  };
71
88
 
72
89
  if let Some(event) = event {
90
+ debug!("Signal {} mapped to lifecycle event: {:?}", signum, event);
73
91
  send_lifecycle_event(event);
92
+ } else {
93
+ debug!("Signal {} not mapped to any lifecycle event", signum);
74
94
  }
75
95
  }
76
96
 
77
97
  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);
80
101
 
81
102
  unsafe {
82
103
  libc::signal(libc::SIGTERM, receive_signal as usize);
@@ -92,6 +113,7 @@ pub fn reset_signal_handlers() -> bool {
92
113
  }
93
114
 
94
115
  pub fn clear_signal_handlers() {
116
+ debug!("Clearing signal handlers");
95
117
  unsafe {
96
118
  libc::signal(libc::SIGTERM, libc::SIG_DFL);
97
119
  libc::signal(libc::SIGINT, libc::SIG_DFL);
@@ -2,7 +2,7 @@
2
2
  Simple example of how you can use the following options:
3
3
 
4
4
  * https://itsi.fyi/middleware/endpoint/
5
- * https://itsi.fyi/middleware/endpoint/controller
5
+ * https://itsi.fyi/middleware/controller
6
6
  * https://itsi.fyi/middleware/endpoint/schemas/
7
7
 
8
8
  to create validated JSON endpoints directly inside Itsi without a dedicated framework
@@ -213,7 +213,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
213
213
 
214
214
  [[package]]
215
215
  name = "itsi-scheduler"
216
- version = "0.2.18"
216
+ version = "0.2.20"
217
217
  dependencies = [
218
218
  "bytes",
219
219
  "derive_more",
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Scheduler
5
- VERSION = "0.2.18"
5
+ VERSION = "0.2.20"
6
6
  end
7
7
  end
@@ -1644,7 +1644,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
1644
1644
 
1645
1645
  [[package]]
1646
1646
  name = "itsi-server"
1647
- version = "0.2.18"
1647
+ version = "0.2.20"
1648
1648
  dependencies = [
1649
1649
  "argon2",
1650
1650
  "async-channel",
@@ -39,7 +39,7 @@ How to identify the client:
39
39
  ```
40
40
  or
41
41
  ```ruby
42
- key: { parameter: { query: { name: "user_id" } } }
42
+ key: { parameter: { query: "user_id" } }
43
43
  ```
44
44
 
45
45
  ### `store_config`
@@ -9,6 +9,7 @@ module Itsi
9
9
  require_relative "default_app/default_app"
10
10
 
11
11
  ITSI_DEFAULT_CONFIG_FILE = "Itsi.rb"
12
+ ITSI_SERVER_PID_DIR = ENV.fetch("ITSI_SERVER_PID_DIR", "tmp")
12
13
 
13
14
  def self.prep_reexec!
14
15
  @argv ||= ARGV[0...ARGV.index("--listeners")]
@@ -248,8 +249,8 @@ module Itsi
248
249
  end
249
250
 
250
251
  def self.pid_file_path
251
- if Dir.exist?("tmp")
252
- File.join("tmp", "itsi.pid")
252
+ if Dir.exist?(ITSI_SERVER_PID_DIR)
253
+ File.join(ITSI_SERVER_PID_DIR, "itsi.pid")
253
254
  else
254
255
  ".itsi.pid"
255
256
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Server
5
- VERSION = "0.2.18"
5
+ VERSION = "0.2.20"
6
6
  end
7
7
  end
@@ -94,6 +94,8 @@ module Itsi
94
94
 
95
95
  def write_pid
96
96
  File.write(Itsi::Server::Config.pid_file_path, Process.pid)
97
+ rescue => e
98
+ Itsi.log_error e.message
97
99
  end
98
100
 
99
101
  def get_pid(warn = true)
data/lib/itsi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Itsi
2
- VERSION = '0.2.18'
2
+ VERSION = "0.2.20"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itsi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.18
4
+ version: 0.2.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.2.18
18
+ version: 0.2.20
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 0.2.18
25
+ version: 0.2.20
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: itsi-server
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.2.18
32
+ version: 0.2.20
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 0.2.18
39
+ version: 0.2.20
40
40
  description: Wrapper Gem for both the Itsi server and the Itsi Fiber scheduler
41
41
  email:
42
42
  - wc@pico.net.nz
@@ -1140,7 +1140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1140
1140
  - !ruby/object:Gem::Version
1141
1141
  version: '3.2'
1142
1142
  requirements: []
1143
- rubygems_version: 3.6.7
1143
+ rubygems_version: 3.6.9
1144
1144
  specification_version: 4
1145
1145
  summary: Wrapper Gem for both the Itsi server and the Itsi Fiber scheduler
1146
1146
  test_files: []