Skip to content

fix(interactive): interrupt and stop arf through IPC instead of signals - #1950

Draft
eitsupi wants to merge 7 commits into
mainfrom
feat/interactive-arf-ipc
Draft

eitsupi wants to merge 7 commits into
mainfrom
feat/interactive-arf-ipc

Conversation

@eitsupi

@eitsupi eitsupi commented Nov 15, 2026

Copy link
Copy Markdown
Member

Note

Draft. Interrupting slow inspection is not done yet, so interrupts a slow inspection and continues serving R requests is expected to fail. That part will move inspection to arf handler calls with execution deadlines, building on #1949, and will be added to this branch before it is ready for review.

Summary

Interrupting an R Interactive submission sends SIGINT to the arf process. Headless arf interrupts R when the signal arrives during an evaluation, but when R is idle the signal ends the whole session. An interrupt that races with the start or the end of an evaluation can therefore kill the session; this is why adopts an existing arf process without losing its objects fails intermittently on Linux and macOS (it was left out of #1943 for this reason).

This PR moves Interactive to arf 0.7.1 and its IPC: interrupts target an arf execution ID instead of signalling the process, and Stop asks arf to shut down.

Changes

  • arf version: Interactive requires arf 0.7.1 or later, with execution deadlines for handler calls (used next for inspection). The session's own arf_version is checked, not the arf on PATH, and older or unknown versions are rejected with a clear message. A TODO records that the minimum should move to 0.7.2 once it is released (it fixes the status of an R error that follows a caught interrupt in visible evaluations, and bounds console reads that cannot be answered).
  • Errors: arfRequest keeps JSON-RPC error codes and data (ArfRpcError) and reports the client giving up separately (ArfTransportTimeoutError), so a server timeout is recognised by its code instead of by matching messages.
  • Execution IDs: the backend opens a long-lived arf connection (arfAttach.ts) and subscribes before submitting code. Before running a submission, sess publishes an event with the submission ID; arf attaches the running execution's ID to it. Managed sessions also get the same ID from the user_input acknowledgement, and a mismatch stops further dispatch.
  • Interrupt: an arf IPC interrupt for that execution ID. A request made before the ID is known is held and sent when it arrives; it is dropped once sess reports completion, so it never reaches a later execution. Acceptance is not treated as the outcome; sess still reports interrupted. With nothing running, interrupt now fails instead of signalling R.
  • Stop: arf shutdown, then wait for the process to exit and kill it after a deadline. An interactive arf rejects shutdown as an unknown method; only that answer makes Stop fall back to SIGTERM and then SIGKILL. Other failures are not taken as a sign that the session is interactive.
  • Bootstrap: the bootstrap evaluation must report status: "ok"; a missing or unknown status is a failure.
  • CI: arf is installed with mise. mise.toml pins the version and mise.lock records each platform's download and checksum, replacing the hand-written download and checksum script. arf is still not installed on Windows.

Notes for reviewers

  • The new test an interrupt between executions does not end the session fails when interrupts are sent as SIGINT (checked locally against arf 0.7.1), so it covers the race behind the flaky test. The existing interrupt tests also pass with SIGINT because they interrupt while R is busy.
  • If the event connection drops, the next submission attaches again and checks that the endpoint still belongs to the same arf process. Code is never resubmitted automatically.
  • Stopping an adopted interactive arf still uses signals on its PID, as before.

arfRequest now rejects with an ArfRpcError that keeps the error code and data,
and with ArfTransportTimeoutError when the client stops waiting, so callers
can tell a server timeout from other failures without matching messages.

Add the version check for Interactive sessions: arf 0.7.1 or later, with
execution deadlines for handler calls. Prereleases count as older than their
release. A TODO records that the minimum should move to 0.7.2 once it is
released.
ArfAttachConnection attaches to arf over newline-delimited JSON-RPC, matches
responses by ID, and delivers events to a listener registered before
attaching, so an event in the same chunk as the attach response is not lost.
A request that times out or is aborted locally may still run in R; its late
response is ignored and its ID is not reused. The connection closes once and
rejects every pending request with the same reason; it never reconnects.
Interrupting an Interactive submission sent SIGINT to the arf process. When
the signal reached headless arf while R was idle, for example just before
evaluation started or after it finished, it ended the whole session; this made
the adopted-session interrupt test fail intermittently.

The backend now attaches to arf before submitting code, and sess publishes an
event with the submission ID before running it, so the event's arf execution
ID identifies the submission (a managed user_input acknowledgement reports the
same ID). An interrupt is sent as an arf IPC interrupt for that ID, held until
the ID is known and dropped once sess reports completion. With nothing
running, interrupt now fails instead of signalling R.

Stop sends arf shutdown, waits for the process to exit and kills it after a
deadline. An interactive arf rejects shutdown as an unknown method, and only
that answer falls back to SIGTERM and then SIGKILL. The bootstrap evaluation
must report status "ok".

Interrupting slow inspection is not supported yet; it will use execution
deadlines of handler calls.
mise.toml pins arf, and mise.lock records the download and checksum for each
platform, replacing the hand-written download and checksum script. arf is
still not installed on Windows. ARF_PATH points at the installed binary.
Also suppress Arity's routine-registration rule where sess calls the arf
routines: they are registered by the embedding host, so there is no package
symbol to bind.

This branch has not been deployed

No deployments
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