omq-backend-rust 0.1.6 → 0.1.7

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: a08620eb9fd1a781752e72f44186bbaee5fcefd37d92560901aa8fb7c6e4f269
4
- data.tar.gz: 891cc692da98d5cd7e2daf2a461e06b4c7b41de91f88964d1d9f7cbc20616f9a
3
+ metadata.gz: b22c5a39d466ddff0ea811bfadff93fe58e64c3ea08bb213f61419e5efd13cc6
4
+ data.tar.gz: '09ef0d2306516c3809a957f61e234360d9f2bbe34b0389cf874c8d5cdc87abc8'
5
5
  SHA512:
6
- metadata.gz: 37745e0ab15d9dabd1ec62262c821951ee489a6bc11f86eee30c355b9fff07909246800e2ac6184379d46bd958258c411a5be55fadaf052af92c7ef01d3e024f
7
- data.tar.gz: 2b89190343754d64b322efa8cbb08f880900324247b87d7b0cbb4df6c5af195caa1da41d3909a32168e8f5ad12f3a82714648a43521e789ea70ff5b053c514c9
6
+ metadata.gz: bae7c0181f01e714d3fbbb11546bb84dc6642d77661734e5d5eaa5467af153a5437b0a9af1ff0d1b8f894609928d7952a83bcb492ef299e327253acdc6a1f85d
7
+ data.tar.gz: b787de3962b49bf2c784596f8fd82901e0323e74270915ba051359eb73a46022389726cea92b1a6364c7780eaf296a457d8355d90507503a5690f4de4de8410b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.1.7] - 2026-08-02
6
+
7
+ ### Added
8
+
9
+ - Restored Rust/Ruby backend interop coverage.
10
+
11
+ ### Changed
12
+
13
+ - Updated to `omq-tokio` 0.21.0.
14
+
15
+ ### Fixed
16
+
17
+ - Drained the Ruby-to-Tokio send pump before native socket close.
18
+ - Released Rust send ring slots before awaiting native sends, avoiding
19
+ high-throughput stalls under `omq-tokio` 0.21.0 backpressure.
20
+ - Waited for Rust peer registration before resolving `peer_connected`.
21
+
5
22
  ## [0.1.6] - 2026-08-01
6
23
 
7
24
  ### Added
@@ -19,7 +19,7 @@ zstd = ["omq-tokio/zstd"]
19
19
 
20
20
  [dependencies]
21
21
  omq-proto = { version = "=0.25.0", default-features = false }
22
- omq-tokio = { version = "=0.20.3", default-features = false }
22
+ omq-tokio = { version = "=0.21.0", default-features = false }
23
23
  tokio = { version = "1.52.0", features = ["rt", "rt-multi-thread", "time", "sync", "io-util", "net"] }
24
24
  yring = { version = "0.3.11", features = ["async"] }
25
25
 
@@ -299,20 +299,15 @@ pub fn materialize(
299
299
  let job: Job = Box::new(move || {
300
300
  let sock = Arc::new(InnerSocket::new(socket_type, options));
301
301
 
302
- const SEND_YIELD_INTERVAL: u32 = 256;
303
302
  let s = sock.clone();
304
303
  let sn = send_notify.clone();
305
304
  let send_pump = tokio::spawn(async move {
306
- futures::pin_mut!(send_cons);
307
- let mut batch = 0u32;
305
+ let mut send_cons = send_cons;
308
306
  while let Some(msg) = futures::StreamExt::next(&mut send_cons).await {
309
- let _ = s.send(msg).await;
307
+ send_cons.release();
310
308
  sn.notify();
311
- batch += 1;
312
- if batch >= SEND_YIELD_INTERVAL {
313
- batch = 0;
314
- tokio::task::yield_now().await;
315
- }
309
+ let _ = s.send(msg).await;
310
+ tokio::task::yield_now().await;
316
311
  }
317
312
  sn.notify();
318
313
  });
@@ -343,6 +338,7 @@ pub fn materialize(
343
338
  });
344
339
 
345
340
  let monitor_sock = sock.clone();
341
+ let peer_ready_sock = sock.clone();
346
342
  let monitor_pump = tokio::spawn(async move {
347
343
  let mut stream = monitor_sock.monitor();
348
344
  let mut peer_count: u32 = 0;
@@ -359,6 +355,7 @@ pub fn materialize(
359
355
  had_peers = true;
360
356
  if !peer_connected_fired {
361
357
  peer_connected_fired = true;
358
+ let _ = peer_ready_sock.connections().await;
362
359
  peer_connected_notify.force_wake();
363
360
  }
364
361
  }
@@ -374,6 +371,12 @@ pub fn materialize(
374
371
  subscriber_joined_notify.force_wake();
375
372
  }
376
373
  }
374
+ omq_tokio::MonitorEvent::JoinReceived { .. } => {
375
+ if !subscriber_joined_fired {
376
+ subscriber_joined_fired = true;
377
+ subscriber_joined_notify.force_wake();
378
+ }
379
+ }
377
380
  _ => {}
378
381
  }
379
382
 
@@ -432,24 +435,59 @@ pub fn destroy_socket(
432
435
  io_threads: usize,
433
436
  sock: Arc<InnerSocket>,
434
437
  send_prod: Mutex<yring::AsyncProducer<omq_tokio::Message>>,
435
- send_pump: JoinHandle<()>,
438
+ mut send_pump: JoinHandle<()>,
436
439
  recv_pump: JoinHandle<()>,
437
440
  monitor_pump: JoinHandle<()>,
438
441
  linger: Option<Duration>,
439
442
  ) {
440
443
  recv_pump.abort();
441
444
  monitor_pump.abort();
442
- send_pump.abort();
443
- drop(send_prod);
444
445
  let Ok(handle) = (|| -> std::result::Result<Handle, ()> { Ok(ensure_runtime(io_threads)) })()
445
446
  else {
447
+ send_pump.abort();
448
+ drop(send_prod);
446
449
  return;
447
450
  };
448
451
  let close_timeout = linger
449
452
  .unwrap_or(Duration::from_secs(30))
450
453
  .max(Duration::from_millis(10));
451
- handle.spawn(async move {
454
+ let fut = async move {
455
+ drop(send_prod);
456
+ if tokio::time::timeout(close_timeout, &mut send_pump)
457
+ .await
458
+ .is_err()
459
+ {
460
+ send_pump.abort();
461
+ let _ = send_pump.await;
462
+ }
463
+
452
464
  let s = Arc::try_unwrap(sock).unwrap_or_else(|arc| (*arc).clone());
453
465
  let _ = tokio::time::timeout(close_timeout, s.close()).await;
466
+ };
467
+
468
+ let (otx, orx) = flume::bounded::<()>(1);
469
+ handle.spawn(async move {
470
+ fut.await;
471
+ let _ = otx.send(());
454
472
  });
473
+
474
+ struct RecvBox {
475
+ rx: flume::Receiver<()>,
476
+ }
477
+
478
+ extern "C" fn blocking_recv(data: *mut libc::c_void) -> *mut libc::c_void {
479
+ let rd = unsafe { &mut *(data as *mut RecvBox) };
480
+ let _ = rd.rx.recv();
481
+ std::ptr::null_mut()
482
+ }
483
+
484
+ let mut rd = RecvBox { rx: orx };
485
+ unsafe {
486
+ rb_sys::rb_thread_call_without_gvl(
487
+ Some(blocking_recv),
488
+ &mut rd as *mut RecvBox as *mut libc::c_void,
489
+ None,
490
+ std::ptr::null_mut(),
491
+ );
492
+ }
455
493
  }
@@ -19,7 +19,7 @@ module OMQ
19
19
  @peer_connected = Async::Promise.new
20
20
  @all_peers_gone = Async::Promise.new
21
21
  @subscriber_joined = Async::Promise.new
22
- @connections = []
22
+ @connections = {}
23
23
  @closed = false
24
24
  @parent_task = nil
25
25
  @on_io_thread = false
@@ -222,6 +222,7 @@ module OMQ
222
222
  monitor_io.wait_readable
223
223
  monitor_io.read_nonblock(256, exception: false)
224
224
  while (data = @native.try_recv_monitor)
225
+ track_connection_event(data)
225
226
  @monitor_queue.enqueue(MonitorEvent.new(**data))
226
227
  end
227
228
  end
@@ -229,6 +230,23 @@ module OMQ
229
230
  end
230
231
 
231
232
 
233
+ def track_connection_event(data)
234
+ detail = data[:detail] || {}
235
+ connection_id = detail[:connection_id]
236
+
237
+ case data[:type]
238
+ when :handshake_succeeded
239
+ @connections[connection_id || Object.new] = true
240
+ when :disconnected
241
+ if connection_id
242
+ @connections.delete(connection_id)
243
+ else
244
+ @connections.shift
245
+ end
246
+ end
247
+ end
248
+
249
+
232
250
  def extract_options
233
251
  h = {}
234
252
  h["send_hwm"] = @options.send_hwm
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OMQ
4
4
  module Rust
5
- VERSION = "0.1.6"
5
+ VERSION = "0.1.7"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omq-backend-rust
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger