Skip to content

src,lib,test: make metrics interval updates thread-safe#472

Open
santigimeno wants to merge 4 commits into
node-v24.x-nsolid-v6.xfrom
santi/interval_thread_safe
Open

src,lib,test: make metrics interval updates thread-safe#472
santigimeno wants to merge 4 commits into
node-v24.x-nsolid-v6.xfrom
santi/interval_thread_safe

Conversation

@santigimeno

@santigimeno santigimeno commented May 18, 2026

Copy link
Copy Markdown
Member

This PR makes runtime metrics interval updates thread-safe and adds regression coverage for the gRPC reconfigure path.

Before this change, interval updates used a separate native setMetricsInterval path. This PR moves interval handling into the normal config update flow and stores the interval state on EnvList, so the metrics timer can safely observe and apply runtime updates.

This keeps interval updates in a single configuration path and avoids updating timer state through a separate unsynchronized mechanism. It also gives us an end-to-end test for the real behavior we care about: changing interval at runtime affects metrics export cadence without restarting the process.

Summary by CodeRabbit

  • Changes
    • Metrics interval is now controlled entirely via the standard configuration (env/package/default), validated as a positive finite number, and applied immediately on reconfigure. The prior standalone interval setter was removed.
  • Tests
    • Added tests for parsing, env/package fallback, persistence, and dynamic reconfiguration including faster-cadence scenarios.

Review Change Stack

Also, move metrics interval state into EnvList.
Refactor NSolid metrics interval handling so configuration
and updates are managed in a single place in JS, and the
native API no longer exposes a separate setMetricsInterval
entry point. This reduces duplicated logic between JS and
C++ and makes interval changes easier to reason about.
@santigimeno santigimeno requested a review from RafaelGSS May 18, 2026 08:58
@santigimeno santigimeno self-assigned this May 18, 2026
@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eb09f3f1-ffa8-484f-9d80-3efd51360abb

📥 Commits

Reviewing files that changed from the base of the PR and between fcf7417 and da61279.

📒 Files selected for processing (5)
  • lib/nsolid.js
  • test/fixtures/nsolid-interval-package.json
  • test/fixtures/test-nsolid-config-interval-env-script.js
  • test/parallel/test-nsolid-config-interval-env.js
  • test/parallel/test-nsolid-config-interval.js
✅ Files skipped from review due to trivial changes (1)
  • test/fixtures/nsolid-interval-package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/fixtures/test-nsolid-config-interval-env-script.js
  • test/parallel/test-nsolid-config-interval.js
  • test/parallel/test-nsolid-config-interval-env.js

Walkthrough

Metrics interval control moved from a JS binding to EnvList configuration: EnvList stores an atomic gen_ptiles_interval_ updated in UpdateConfig(), the ptiles timer uses that atomic value and restarts when changed, JS parses/stores top-level interval, and tests validate normalization and reconfigure cadence.

Changes

Metrics Interval Reconfiguration Migration

Layer / File(s) Summary
Atomic interval field and config reading
src/nsolid/nsolid_api.h, src/nsolid/nsolid_api.cc
Add gen_ptiles_interval_ atomic member to EnvList (init 5000 ms), remove the global interval constant usage, and read "interval" from config in EnvList::UpdateConfig().
Timer initialization and dynamic interval restart
src/nsolid/nsolid_api.cc
Start gen_ptiles_timer_ using gen_ptiles_interval_.load() and update gen_ptiles_cb_ to accept the timer handle, compare the timer repeat with the configured atomic interval, and restart the timer when they differ.
JS config parsing/coercion and binding removal
lib/nsolid.js, src/nsolid/nsolid_api.cc
initializeConfig() and updateConfig() parse/coerce interval via parsePositiveFiniteNumber() and persist it on nsolidConfig.interval; the post-update binding.setMetricsInterval() call is removed and the C++ setMetricsInterval JS binding registration is deleted.
Integration and parallel tests for interval behavior
test/agents/test-grpc-metrics-interval-reconfigure.mjs, test/parallel/*, test/fixtures/*
Add an end-to-end gRPC reconfigure test that switches metrics interval and asserts faster metrics cadence; add parallel/env tests and fixtures validating interval normalization, package-derived interval, and preservation across invalid/partial updates.

Sequence Diagram(s)

sequenceDiagram
  participant GRPCClient
  participant GRPCServer
  participant EnvList
  participant gen_ptiles_timer
  GRPCClient->>GRPCServer: reconfigure(agentId, { interval: NEW })
  GRPCServer->>EnvList: UpdateConfig({ interval: NEW })
  EnvList->>EnvList: gen_ptiles_interval_.store(NEW)
  EnvList->>gen_ptiles_timer: uv_timer_get_repeat() vs gen_ptiles_interval_.load()
  alt intervals differ
    EnvList->>gen_ptiles_timer: stop & start with NEW repeat
  end
  gen_ptiles_timer->>GRPCServer: emit metrics at new cadence
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

QA approved

Suggested reviewers

  • RafaelGSS
  • EHortua

Poem

🐰 A tiny tick learns a brand-new tune,
Atomics set tempo under sun and moon,
Bindings stepped back so timers may steer,
New tests listen close to prove the beat clear,
Hooray—metrics hop to a steadier cheer.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the primary objective—making metrics interval updates thread-safe through consolidated configuration handling—and directly aligns with the main changes across lib/nsolid.js, src/nsolid/nsolid_api.cc, and supporting infrastructure.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch santi/interval_thread_safe

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/nsolid.js`:
- Around line 773-775: The code assigns nsolidConfig.interval = +config.interval
without validation, allowing NaN/Infinity/0/negative values; update the branch
that handles key === 'interval' to parse and validate config.interval (e.g.,
Number(config.interval) or parseFloat) and only assign if Number.isFinite(value)
&& value > 0, otherwise skip assignment or leave the existing
nsolidConfig.interval unchanged (or set a safe default); reference the
'interval' branch, the nsolidConfig object, and config.interval when making this
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b6bf2c7-87ad-443b-9cdc-ced5b188e705

📥 Commits

Reviewing files that changed from the base of the PR and between ac25445 and 66f4181.

📒 Files selected for processing (4)
  • lib/nsolid.js
  • src/nsolid/nsolid_api.cc
  • src/nsolid/nsolid_api.h
  • test/agents/test-grpc-metrics-interval-reconfigure.mjs

Comment thread lib/nsolid.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
lib/nsolid.js (1)

1172-1195: ⚡ Quick win

Use this parser in startup initialization too for consistent interval semantics.

parsePositiveFiniteNumber() is solid, but startup still uses permissive coercion in initializeConfig() (Line 915), so invalid/negative env or package values can bypass this validation path. Reusing this helper there keeps startup and runtime behavior aligned.

Proposed minimal diff
-  nsolidConfig.interval =
-    +process.env.NSOLID_INTERVAL ||
-    pkgConfig.nsolid.interval ||
-    DEFAULT_INTERVAL;
+  const envInterval = parsePositiveFiniteNumber(process.env.NSOLID_INTERVAL);
+  const pkgInterval = parsePositiveFiniteNumber(pkgConfig.nsolid.interval);
+  nsolidConfig.interval = envInterval ?? pkgInterval ?? DEFAULT_INTERVAL;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/nsolid.js` around lines 1172 - 1195, Startup initialization currently
coerces env/package interval values permissively; update initializeConfig to
call parsePositiveFiniteNumber when interpreting numeric configuration (e.g.,
interval, timeout) instead of using direct +value or permissive coercion so
negative, NaN, empty-string or non-finite inputs return undefined; locate
initializeConfig and replace the existing numeric coercion logic with a call to
parsePositiveFiniteNumber(value) and handle its undefined return the same way
startup treats missing config.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@lib/nsolid.js`:
- Around line 1172-1195: Startup initialization currently coerces env/package
interval values permissively; update initializeConfig to call
parsePositiveFiniteNumber when interpreting numeric configuration (e.g.,
interval, timeout) instead of using direct +value or permissive coercion so
negative, NaN, empty-string or non-finite inputs return undefined; locate
initializeConfig and replace the existing numeric coercion logic with a call to
parsePositiveFiniteNumber(value) and handle its undefined return the same way
startup treats missing config.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4441d74e-5b09-4087-9135-c409c9898791

📥 Commits

Reviewing files that changed from the base of the PR and between 66f4181 and b5397f8.

📒 Files selected for processing (2)
  • lib/nsolid.js
  • test/parallel/test-nsolid-config-interval.js

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 18, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
test/parallel/test-nsolid-config-interval-env.js (1)

33-72: ⚡ Quick win

Consider adding test cases for standalone negative interval and env-package precedence.

The current test coverage is solid, but two additional scenarios would strengthen it:

  1. Standalone negative NSOLID_INTERVAL (without NSOLID_PACKAGE_JSON): Currently tested with package.json (lines 66-72), but not alone. Adding a test for NSOLID_INTERVAL: '-1' without package should verify fallback to 5000, similar to the zero test (lines 52-57).

  2. Valid NSOLID_INTERVAL overriding package value: Test precedence when both NSOLID_PACKAGE_JSON (3000) and a valid NSOLID_INTERVAL (e.g., '2500') are provided to clarify which source takes priority.

📋 Suggested additional test cases
// Test standalone negative interval falls back to default
{
  const config = runWithEnv({
    NSOLID_INTERVAL: '-1',
  });
  assert.strictEqual(config.interval, 5000);
}

// Test valid env interval overrides package-derived value
{
  const config = runWithEnv({
    NSOLID_PACKAGE_JSON: pkgJson,
    NSOLID_INTERVAL: '2500',
  });
  assert.strictEqual(config.interval, 2500); // or 3000 if package wins
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/parallel/test-nsolid-config-interval-env.js` around lines 33 - 72, Add
two tests to cover missing negative-interval and env-vs-package precedence:
create a case calling runWithEnv with NSOLID_INTERVAL: '-1' only and assert
config.interval === 5000 to ensure negative env values fall back to default, and
another case calling runWithEnv with both NSOLID_PACKAGE_JSON: pkgJson and
NSOLID_INTERVAL: '2500' and assert config.interval === 2500 to verify a valid
NSOLID_INTERVAL overrides the package-derived interval; reference runWithEnv,
NSOLID_INTERVAL, NSOLID_PACKAGE_JSON and the config.interval assertions when
adding these tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/parallel/test-nsolid-config-interval-env.js`:
- Around line 33-72: Add two tests to cover missing negative-interval and
env-vs-package precedence: create a case calling runWithEnv with
NSOLID_INTERVAL: '-1' only and assert config.interval === 5000 to ensure
negative env values fall back to default, and another case calling runWithEnv
with both NSOLID_PACKAGE_JSON: pkgJson and NSOLID_INTERVAL: '2500' and assert
config.interval === 2500 to verify a valid NSOLID_INTERVAL overrides the
package-derived interval; reference runWithEnv, NSOLID_INTERVAL,
NSOLID_PACKAGE_JSON and the config.interval assertions when adding these tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d1332c28-d5ec-4f0d-bf25-c1f5ae7f69c9

📥 Commits

Reviewing files that changed from the base of the PR and between b5397f8 and fcf7417.

📒 Files selected for processing (5)
  • lib/nsolid.js
  • test/fixtures/nsolid-interval-package.json
  • test/fixtures/test-nsolid-config-interval-env-script.js
  • test/parallel/test-nsolid-config-interval-env.js
  • test/parallel/test-nsolid-config-interval.js
✅ Files skipped from review due to trivial changes (1)
  • test/fixtures/nsolid-interval-package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/parallel/test-nsolid-config-interval.js
  • lib/nsolid.js

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 18, 2026
Validate interval updates in lib/nsolid.js before assigning them to
nsolidConfig.interval.

Ignore invalid values such as 0, negative numbers, NaN, Infinity, and
non-numeric strings so the previous valid interval is preserved.

Add a parallel test covering valid coercion, invalid updates, and
partial updates that omit interval.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant