galaaz 2.1.3 → 2.1.5

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.
@@ -15,12 +15,13 @@ describe 'gknit install timeout reporting' do
15
15
  path = ([*extra, path].join(File::PATH_SEPARATOR)) unless extra.empty?
16
16
  ENV.to_h.merge(
17
17
  'JAVA_OPTS' => '--add-opens=java.base/java.nio=ALL-UNNAMED',
18
- 'PATH' => path
18
+ 'PATH' => path,
19
+ # Job await limit (bridge --bridge_timeout_sec no longer drives CRAN installs).
20
+ 'GALAAZ_INSTALL_TIMEOUT_SEC' => '1'
19
21
  )
20
22
  end
21
23
 
22
24
  it 'continues processing and prints timeout in final report' do
23
- skip('Temporarily skipped: installation timeout behavior will be reviewed in a dedicated pass')
24
25
  root = File.expand_path('..', __dir__)
25
26
  workdir = Dir.mktmpdir('gknit_install_timeout_', root)
26
27
 
@@ -34,11 +35,28 @@ describe 'gknit install timeout reporting' do
34
35
  ---
35
36
 
36
37
  ```{ruby setup_stub}
37
- R.bridge.eval_r("install.packages <- function(...) { Sys.sleep(2); invisible(NULL) }")
38
+ # Deterministic slow "install": child Rscript sleeps instead of CRAN work.
39
+ # Use ::R — bare R in chunks is RC::R (gknit scope), not the Galaaz module.
40
+ module ::R
41
+ class Job
42
+ def self.install(*packages, lib_dir: default_lib_dir, repos: DEFAULT_REPOS, wait: true, timeout: nil, &block)
43
+ pkgs = packages.flatten.map(&:to_s).reject(&:empty?)
44
+ raise ArgumentError, 'R::Job.install requires at least one package name' if pkgs.empty?
45
+
46
+ FileUtils.mkdir_p(lib_dir)
47
+ FileUtils.mkdir_p(jobs_root)
48
+ with_install_lock do
49
+ job = new(kind: 'install', packages: pkgs, lib_dir: lib_dir)
50
+ job.send(:spawn_eval!, 'Sys.sleep(30)')
51
+ finish_job(job, wait: wait, timeout: timeout, &block)
52
+ end
53
+ end
54
+ end
55
+ end
38
56
  ```
39
57
 
40
58
  ```{ruby timeout_install}
41
- R.install_and_loads('definitely_fake_pkg_for_timeout_spec')
59
+ ::R.install_and_loads('definitely_fake_pkg_for_timeout_spec')
42
60
  ```
43
61
 
44
62
  ```{ruby after_timeout}
@@ -49,18 +67,20 @@ describe 'gknit install timeout reporting' do
49
67
  rel_rmd = File.basename(workdir) + '/' + File.basename(rmd_path)
50
68
  out, err, st = Open3.capture3(
51
69
  self.class.gknit_env,
52
- 'bin/gknit', '--output_format', 'github_document', '--bridge_timeout_sec', '1', rel_rmd,
70
+ 'bin/gknit', '--output_format', 'github_document',
71
+ '--install_timeout_sec', '1',
72
+ rel_rmd,
53
73
  chdir: root
54
74
  )
55
75
 
56
76
  md_path = File.join(workdir, 'install_timeout.md')
57
- expect(st.success?).to be(true)
77
+ expect(st.success?).to be(true), "gknit failed (status=#{st.exitstatus}):\n#{err}\n#{out}"
58
78
  expect(File.exist?(md_path)).to be(true)
59
79
  md = File.read(md_path)
60
80
  expect(md).to include('AFTER_TIMEOUT_CHUNK_OK')
61
81
  expect(err).to include('gknit internal errors detected:')
62
82
  expect(err).to include('chunk=timeout_install')
63
- expect(err).to include('no RET for')
83
+ expect(err).to match(/install job timed out/i)
64
84
  expect(out).not_to be_nil
65
85
  ensure
66
86
  FileUtils.rm_rf(workdir) if workdir && File.directory?(workdir)
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Fast R::Job coverage (child Rscript; bridge stays free).
4
+ # Run: bin/run_rspec specs/r_job_spec.rb
5
+
6
+ require 'fileutils'
7
+ require 'tmpdir'
8
+ require 'galaaz'
9
+
10
+ describe 'R::Job' do
11
+ around do |example|
12
+ Dir.mktmpdir('galaaz_jobs_') do |jobs|
13
+ old = ENV['GALAAZ_JOBS_DIR']
14
+ ENV['GALAAZ_JOBS_DIR'] = jobs
15
+ begin
16
+ example.run
17
+ ensure
18
+ ENV['GALAAZ_JOBS_DIR'] = old
19
+ end
20
+ end
21
+ end
22
+
23
+ it 'awaits eval in a block and load_rds on the bridge' do
24
+ coef = R::Job.eval(<<~R) { |job| job.load_rds }
25
+ fit <- lm(mpg ~ wt, data = mtcars)
26
+ saveRDS(unname(coef(fit)), result_path)
27
+ R
28
+
29
+ expect(coef).to be_a(R::Vector)
30
+ expect(coef.length).to eq(2)
31
+ end
32
+
33
+ it 'returns a Job without a block and supports wait: false' do
34
+ job = R::Job.eval('Sys.sleep(0.2); saveRDS(42L, result_path)', wait: false, timeout: 30)
35
+ expect(job).to be_a(R::Job)
36
+ expect(job.alive? || !job.finished?).to eq(true)
37
+
38
+ job.wait(timeout: 30)
39
+ job.raise_if_failed!
40
+ expect(job.status).to eq(:ok)
41
+ expect(job.load_rds.to_s).to include('42')
42
+ end
43
+
44
+ it 'kills the child process group on await timeout' do
45
+ expect {
46
+ R::Job.eval('Sys.sleep(30)', wait: true, timeout: 1)
47
+ }.to raise_error(R::Job::Timeout, /still running after/)
48
+ end
49
+
50
+ it 'runs a script with trailing args and load_rds' do
51
+ Dir.mktmpdir('galaaz_job_script_') do |dir|
52
+ path = File.join(dir, 'train.R')
53
+ File.write(path, <<~R)
54
+ args <- commandArgs(trailingOnly = TRUE)
55
+ n <- as.integer(args[[1]])
56
+ saveRDS(n, result_path)
57
+ R
58
+
59
+ n = R::Job.script(path, '7') { |job| job.load_rds }
60
+ expect(n.to_s).to include('7')
61
+ end
62
+ end
63
+
64
+ it 'clears a stale 00LOCK before install' do
65
+ Dir.mktmpdir('galaaz_job_lib_') do |lib|
66
+ lock = File.join(lib, '00LOCK-definitely_not_a_cran_pkg_xyzzy')
67
+ FileUtils.mkdir_p(lock)
68
+ File.write(File.join(lock, 'marker'), 'stale')
69
+
70
+ job = R::Job.install(
71
+ 'definitely_not_a_cran_pkg_xyzzy',
72
+ lib_dir: lib,
73
+ wait: true,
74
+ timeout: 120
75
+ )
76
+
77
+ expect(File.exist?(lock)).to eq(false)
78
+ expect(job.status).to eq(:failed)
79
+ end
80
+ end
81
+ end
data/version.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  $gem_name = "galaaz"
2
- $version="2.1.3"
2
+ $version="2.1.5"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: galaaz
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.3
4
+ version: 2.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Botafogo
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-09-04 00:00:00.000000000 Z
10
+ date: 2026-09-07 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: msgpack
@@ -310,6 +310,7 @@ files:
310
310
  - lib/R_interface/new_bridge_adapter.rb
311
311
  - lib/R_interface/r.rb
312
312
  - lib/R_interface/r_arrow.rb
313
+ - lib/R_interface/r_job.rb
313
314
  - lib/R_interface/r_libs.R
314
315
  - lib/R_interface/r_methods.rb
315
316
  - lib/R_interface/r_module_s.rb
@@ -450,6 +451,7 @@ files:
450
451
  - specs/r_eval.spec.rb
451
452
  - specs/r_function.spec.rb
452
453
  - specs/r_instance_manager_spec.rb
454
+ - specs/r_job_spec.rb
453
455
  - specs/r_list_apply.spec.rb
454
456
  - specs/r_matrix.spec.rb
455
457
  - specs/r_nse.spec.rb