Skip to content

feat(client): generate local machine id and send x-machine-id on all connections - #1729

Closed
mikhailm-coder wants to merge 1 commit into
mainfrom
hotfix/machine-id-header-client
Closed

feat(client): generate local machine id and send x-machine-id on all connections#1729
mikhailm-coder wants to merge 1 commit into
mainfrom
hotfix/machine-id-header-client

Conversation

@mikhailm-coder

@mikhailm-coder mikhailm-coder commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Ports the machine-id-header client work from openframe-oss-tenant (hotfix/machine-id-header) into oss-lib's copy of the openframe-client crate — this is the repo releases are cut from, and the porting round #1725 didn't carry it (the work lives on a branch in oss-tenant, not merged to its main, so the merged-commit ports never saw it).

What it does

  • New MachineIdService: generates a local Uuid::v4(), persists it to the shared app-support machine_id file (read by the mesh/fleet tool agents), cached behind an Arc<RwLock>.
  • Sends it as the x-machine-id header on the HTTP clients (main + download), the NATS control connection, and the NATS log stream (replacing the "openframe-client" placeholder).
  • The server-assigned machine_id still names the NATS connection; only the header value is the new local id.

Scope / notes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a persistent machine identifier for the application.
    • Included the machine identifier in HTTP and log-streaming connections.
    • Reused the identifier across sessions by loading it from local application storage.
    • Added validation and error handling for machine identifier storage and retrieval.

…connections

Port of the machine-id-header client work from openframe-oss-tenant
(hotfix/machine-id-header). MachineIdService persists a locally
generated UUID in the shared app-support dir (read by mesh/fleet tool
agents) and stamps it as x-machine-id on the HTTP clients, the NATS
connection, and the NATS log stream (replacing the openframe-client
placeholder). The server-assigned machine_id still names the NATS
connection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The client now persists and caches a UUID machine ID. It sends this ID through HTTP and NATS headers. NATS connections retain the configured ID as their connection name.

Changes

Machine ID propagation

Layer / File(s) Summary
Machine ID service and exports
clients/openframe-client/src/services/machine_id_service.rs, clients/openframe-client/src/services/mod.rs
MachineIdService generates, validates, caches, and persists the machine ID. The service and MACHINE_ID_HEADER are publicly re-exported.
Client and NATS connection wiring
clients/openframe-client/src/lib.rs, clients/openframe-client/src/services/nats_connection_manager.rs
Client::new applies the machine ID to both HTTP clients. NatsConnectionManager uses the local ID for MACHINE_ID_HEADER and retains the configured ID as the connection name.
NATS logging authentication
clients/openframe-client/src/logging/nats_streaming.rs
LogStreamingRunManager obtains the machine ID and passes it to NatsLogConnection, which uses the shared header constant.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MachineIdService
  participant HTTPClients
  participant NatsConnectionManager
  participant LogStreamingRunManager
  participant NatsLogConnection

  Client->>MachineIdService: get_or_create machine ID
  Client->>HTTPClients: set MACHINE_ID_HEADER
  Client->>NatsConnectionManager: pass MachineIdService
  NatsConnectionManager->>MachineIdService: get machine ID
  NatsConnectionManager->>NatsConnectionManager: set NATS machine ID header
  LogStreamingRunManager->>MachineIdService: get_or_create machine ID
  LogStreamingRunManager->>NatsLogConnection: pass machine ID
  NatsLogConnection->>NatsLogConnection: set MACHINE_ID_HEADER
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes local machine ID generation and propagation across client connections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 hotfix/machine-id-header-client

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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 `@clients/openframe-client/src/services/machine_id_service.rs`:
- Around line 28-43: Update MachineIdService::get_or_create to propagate read
errors other than NotFound instead of generating a replacement ID. For a missing
file, serialize initialization across processes using an interprocess lock or
atomic create-and-re-read, write the generated ID through a temporary file, and
atomically rename it into place; then cache and return the persisted winner so
concurrent service instances share one machine ID. Implement the same behavior
in the upstream tenant repository first, then port it 1:1 here.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4217d3de-55a4-448e-a69d-484acfe4888c

📥 Commits

Reviewing files that changed from the base of the PR and between 47481ee and 2caf80d.

📒 Files selected for processing (5)
  • clients/openframe-client/src/lib.rs
  • clients/openframe-client/src/logging/nats_streaming.rs
  • clients/openframe-client/src/services/machine_id_service.rs
  • clients/openframe-client/src/services/mod.rs
  • clients/openframe-client/src/services/nats_connection_manager.rs

Comment on lines +28 to +43
pub fn get_or_create(&self) -> Result<String> {
if let Some(id) = self.cached_id.read().unwrap().clone() {
return Ok(id);
}

if let Ok(id) = self.read() {
debug!("Using existing machine ID: {}", id);
*self.cached_id.write().unwrap() = Some(id.clone());
return Ok(id);
}

let id = Uuid::new_v4().to_string();
self.write(&id)?;
info!("Generated new machine ID: {}", id);
*self.cached_id.write().unwrap() = Some(id.clone());
Ok(id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Create the persisted machine ID atomically.

Line 33 ignores every read error. An empty, unreadable, or transiently unavailable file then causes Lines 39-42 to generate a new ID.

Concurrent callers can also both observe a missing file and write different IDs. The RwLock does not protect the full read-create-write sequence across service instances or processes. HTTP, NATS control, and NATS logs can then use different x-machine-id values.

Generate only when the file is NotFound. Serialize initialization with an interprocess lock or atomic create-and-re-read. Write through a temporary file and rename it atomically.

Based on learnings, implement this behavior in the upstream tenant repository first, then retain a 1:1 port here.

🤖 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 `@clients/openframe-client/src/services/machine_id_service.rs` around lines 28
- 43, Update MachineIdService::get_or_create to propagate read errors other than
NotFound instead of generating a replacement ID. For a missing file, serialize
initialization across processes using an interprocess lock or atomic
create-and-re-read, write the generated ID through a temporary file, and
atomically rename it into place; then cache and return the persisted winner so
concurrent service instances share one machine ID. Implement the same behavior
in the upstream tenant repository first, then port it 1:1 here.

Source: Learnings

@mikhailm-coder

Copy link
Copy Markdown
Contributor Author

Folded into #1688, which now covers both the bundled mesh core (with the Host fix) and the openframe-client machine-id work as a single oss-lib PR. Deleting this branch.

@mikhailm-coder
mikhailm-coder deleted the hotfix/machine-id-header-client branch August 14, 2026 14:30
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