NEWS
rgrpc 0.1.2
- The package installs where gRPC C++ cannot be linked, as a stub whose
functions error; the new
grpc_available() reports which build is
installed, and tests and examples skip on a stub. CRAN's macOS
builders have no gRPC, and its libc++ clang builders have only a
libstdc++ gRPC, which linked into a shared object that then failed to
load. configure now links a test program with R's own C++ compiler
instead of trusting pkg-config alone. RGRPC_REQUIRE_GRPC=true turns
the stub fallback into an install error; CI sets it on the legs that
have gRPC and adds a leg without it.
- The
.Call routine table moved to src/routines.h, shared by the real
build and the stub.
- gRPC is initialized once, when the DLL loads, and shut down at unload
or R exit, instead of coming up and down with every client and server.
Each start ran abseil's debug deadlock bookkeeping, whose
frame-pointer stack walk read uninitialized stack through the
package's frames on builds without frame pointers: the valgrind
reports on CRAN's Fedora machine. Fork behavior is unchanged
(
tools/fork-probe.sh).
configure compiles its gRPC link test with R's PIC flags, so a
-pie in LDFLAGS no longer fails it on hardened toolchains.
configure checks for pkg-config with pkg-config --version rather
than command -v, which R-devel's check flags as a possible bashism.
- On macOS the package links CoreFoundation, which a static abseil (as
in CRAN's macOS recipes) needs but does not list in its pkg-config
files.
- SystemRequirements names the Fedora (
grpc-cpp, grpc-devel,
protobuf-devel) and Homebrew packages as well as the Debian ones.
- The TLS tests set certificate extensions explicitly, so they pass
with OpenSSL 1.1, OpenSSL 3, and LibreSSL, and stop cleanly if the
certificates cannot be generated.
configure drops warning options from pkg-config's flags and passes
the include directories as -isystem. abseil's .pc files carry its
own -Wno-... options, which R CMD check reported as non-portable
flags, and gRPC 1.83's headers raise deprecation warnings against
newer abseil releases (Homebrew), which it reported as the package's.
- CI installs
checkbashisms on macOS, targets the runner's macOS when
linking Homebrew's gRPC, and fails on check WARNINGs.
rgrpc 0.1.1 (2026-09-17)
- First CRAN release, resubmitted after the review of 0.1.0. DESCRIPTION links the
gRPC project and its C++ API; every exported function documents its
return value, including the seven called for their side effects; and
the examples run instead of sitting in
\dontrun{}: each one drives a
client and a server in the same process over the loopback interface.
grpc_tls() keeps a \dontrun{} example because it needs certificate
files.
rgrpc 0.1.0
- Renamed from
grpc to rgrpc before the first release: the bare
name is a search token owned by the upstream project, and a unique
name keeps this package's docs and issues findable. Exported
functions keep their grpc_* names.
- First CRAN submission (returned for documentation fixes; see 0.1.1):
an asynchronous gRPC client and server runtime on
the generic C++ API, with unary and streaming calls, TLS/mTLS,
deadlines, keepalive, cancellation, and event-loop integration via
grpc_fd(). Runs on Linux, Windows (Rtools >= 4.3), and macOS.
The 0.0.1.x entries below record the development history.
rgrpc 0.0.1.14
- The package builds on Windows and macOS. The completion wake-up was
the one platform-bound piece of the runtime: eventfd is Linux-only,
and
src/wake.h replaces it with the same contract everywhere -- a
self-pipe on Unix, a loopback socket pair on Windows, readable
exactly while events are queued. Windows links the gRPC that
Rtools >= 4.3 bundles, through a static Makevars.win, and
OS_type: unix left DESCRIPTION. CI gains a macOS leg building
against Homebrew's gRPC.
rgrpc 0.0.1.13
- Depends dropped from R (>= 4.4.0) to R (>= 4.3.0), the version noble
ships. (This heading was added retroactively; the bump rode with the
change in #23 without a NEWS entry.)
rgrpc 0.0.1.12
grpc_await() now works on a server "grpc_request" too, closing the
asymmetry 0.0.1.11 left behind: the docs said "one queue serves the
whole client or server" while the remedy shipped for the client
only, so a server driving concurrent streaming calls still hand-rolled
the id dispatch that had already gone wrong five times downstream.
A handler can drain one client-streaming call with
grpc_await(req, timeout_ms) and see nothing belonging to any other.
grpc_await() became an S3 generic to accommodate that third class.
Call sites are unaffected: the signature is unchanged and the existing
"grpc_call" and "grpc_stream" behaviour is identical.
- On a server request the awaited events are the ones that follow the
request itself (
"stream_msg", "client_done", "stream_writable",
"cancelled"), since the request arrives from grpc_poll() in the
first place. A server call has no terminal event of its own -- it ends
when the handler ends it -- so "client_done" is what a
client-streaming handler loops to.
rgrpc 0.0.1.11
- New
grpc_await(x, timeout_ms): waits for events belonging to one
call or stream. Other calls' events are stepped over and left queued
in arrival order, and the wait ends only when a matching event
arrives. This is the demultiplexing every other gRPC binding does
for you -- Python hands back a per-call future or response iterator
and never exposes a completion queue -- and its absence is what made
the attribution mistakes in 0.0.1.10 possible in the first place.
Use it for sequential code; use grpc_poll() and dispatch on id
when calls really are concurrent, since awaiting one call means not
looking at the others.
- The filter lives in C over the existing ready deque rather than in
an R-side buffer, so there is no second queue to keep in sync and a
filtered read cannot lose or reorder another call's events. The wait
is filter-aware: it cannot lean on the eventfd, because another
call's queued events keep the descriptor readable and the wait would
spin instead of blocking.
- An expired
grpc_await() leaves the call exactly as it was: await it
again to keep waiting. That resumability is what keeps a required
timeout_ms from being the empty-batch trap in new clothing, so it
is now stated rather than implied, along with which clock is which
(deadline_ms bounds the RPC, timeout_ms bounds one wait).
Examples check the batch before indexing it: on a slow peer
grpc_await(call, timeout_ms = 1000)[[1]] raises subscript out of bounds, which reads like a caller bug rather than the timeout it is.
- The documentation stopped teaching the bug. The README's round-trip
and typed-call examples, and
inst/examples/cri-list-pods.R, all
indexed a poll batch as evs[[1]] or hand-rolled a drain() helper
that returned the first event of whatever arrived. Correct only
while nothing else is in flight, which is exactly how a caller
infers the wrong model.
rgrpc 0.0.1.10
- Fixed spurious wake-ups from
grpc_poll() (#12). The eventfd
carries one signal per event, but the counter was drained outside
the mutex guarding the ready deque, so every signal posted between
the drain and the batch below stayed counted even though the batch
took those events. The leftover count was then spent as instant,
empty polls: a caller that reads "no events" as "this call never
started" abandons a live stream, which showed up as sequential
server-streaming calls on a shared client failing 1-7 times in 30.
The drain and a re-arm now happen under that mutex, so the
descriptor is readable exactly while events are queued. Affects
clients and servers alike, and grpc_fd() integrations most of all,
since a partial batch used to leave the descriptor unreadable with
events still pending.
- Documented what an empty
grpc_poll() result means: the wait
expired, not that the call is over.
- Documented event attribution: one queue serves the whole client, so
a batch can mix events from every call in flight, in completion
order, and callers must dispatch on
id. Taking events[[1]] as
the answer to a unary call and accumulating every "stream_msg"
into one stream's payload are the same assumption -- one queue per
call -- and it does not hold. Abandoning a stream unread does not
stop it, and
its queued messages go on surfacing alongside later calls;
grpc_cancel() bounds how many more are produced but cannot recall
events already queued. Verified against the runtime rather than
assumed: over 40 rounds of a deliberately abandoned stream followed
by a second stream on the same client, no event's id ever
disagreed with its payload, while an accumulator that ignored id
got the wrong byte count 36 times out of 40.
rgrpc 0.0.1.9
- Fixed a use-after-free race found by the first genuinely
instrumented ThreadSanitizer run:
grpc_r_call_start() and
grpc_r_stream_start() read the call id after releasing the mutex,
and a fast completion can free the call state on the drain thread in
that window. The id is now captured under the lock.
tools/sanitize.sh is fail-closed about its own preconditions,
after three stacked silent failures let earlier sanitizer passes run
the plain build: libraries are injected via R_LIBS and asserted
with find.package() (littler's -L silently does not prepend),
sanitizer flags go through CXX17FLAGS and instrumentation is
proven via __asan/__tsan symbols in the built .so, installs
use --preclean, an exit trap removes flagged objects even on
failure, non-data-race TSan warnings are fatal, and the report
classifier self-tests against synthetic logs at every run.
rgrpc 0.0.1.8
- Keepalive:
keepalive_ms/keepalive_timeout_ms on grpc_client()
and grpc_server(), plus min_ping_interval_ms (server tolerance
for client pings; gRPC's default is 5 minutes and kills faster
clients). Enabling keepalive also lifts gRPC's ping policing so
pings flow on quiet connections.
- Abortive close:
grpc_finish(drain = FALSE) discards queued stream
writes and prioritizes the terminal status (fencing); grpc_cancel()
now also works on server requests as the hard escalation past a peer
that has stopped reading.
rgrpc 0.0.1.7
- Fixed a completion-queue shutdown race that aborted the process when
closing a client (or server) with stream operations in flight: the
drain thread could post a follow-on op after
cq.Shutdown(). A
shutting flag now suppresses all drain-thread op posts during
close, on both client and server.
- Forced-error cleanup tests: post-close operations error cleanly,
finalizers with work in flight, create/destroy churn.
- Verified under valgrind (0 errors, 0 definite/indirect leaks;
possibly-lost noise from gRPC/absl thread-locals and R
remains), AddressSanitizer
(clean), and ThreadSanitizer (all reports trace to the
uninstrumented system libgrpc boundary; none in package code).
- Reference node image under
docker/: two-stage build on
rocker/r2u:noble, runtime carries only libgrpc++1.51t64 and
r-cran-rprotobuf; built and smoke-tested. The base image release
must match the build host's — the binary is tied to the distro ABI.
- configure and
SystemRequirements now name libprotobuf-dev
alongside libgrpc++-dev (not pulled automatically under
--no-install-recommends).
rgrpc 0.0.1.6
- Operational surface:
grpc_tls() builds PEM credentials for both
sides (TLS server, CA-pinned client, mTLS with
require_client_cert, target_name_override for testing); server
request events carry the transport peer and, under mTLS, the
verified peer_identity; grpc_state() observes channel
connectivity; GRPC_TRACE/GRPC_VERBOSITY documented.
- Health checking (
grpc.health.v1) and server reflection
(grpc.reflection.v1) protos vendored and proven through the
generic path — unary Check and bidi ServerReflectionInfo — with no
special machinery.
rgrpc 0.0.1.5
- Streaming:
grpc_stream() opens client-, server-, and bidirectional
streams (typed or raw); grpc_send() (bounded write queue with
stream_writable backpressure events), grpc_writes_done(),
automatic bounded inbound buffering with HTTP/2 backpressure, and a
terminal stream_status event. Server side: grpc_read() pulls
inbound stream messages, grpc_send() queues outbound ones,
grpc_finish() ends the stream after writes drain. grpc_cancel()
is now a generic over calls and streams; client events carry kind.
- Live CRI streaming smoke: subscribe, hold, and cancel
GetContainerEvents against containerd.
rgrpc 0.0.1.4
- Real-world proof: CRI client against live containerd (v2.2.3) over a
unix-domain socket —
Version, ListPodSandbox, ListImages, all
through the typed layer. CRI v1 schema vendored as a self-contained
import root under inst/proto/cri; live tests gate on socket access
(GRPC_R_CRI_SOCKET); inst/examples/cri-list-pods.R for humans.
- PLAN.md: Viento experiment reframed as control-plane candidacy.
rgrpc 0.0.1.3
- RProtoBuf integration:
grpc_service() / grpc_method() resolve
services and methods from the runtime descriptor pool (via the
FileDescriptorProto, sidestepping rprotobuf#116); grpc_call()
accepts a grpc_method plus a Message, validates the request type,
and auto-decodes OK responses as response_message; grpc_reply()
accepts a Message; grpc_decode() decodes payload bytes. RProtoBuf
remains a Suggests.
rgrpc 0.0.1.2
- Generic asynchronous server on
AsyncGenericService: grpc_server()
accepts any method dynamically; grpc_reply() answers with a payload
or a typed status plus trailing metadata. Bounded accept window and
max_active apply backpressure.
grpc_poll(), grpc_fd(), grpc_pending(), and grpc_close() are
now S3 generics over clients and servers. Peer cancellation and
deadline expiry surface as "cancelled" events; late replies are
refused rather than crashing.
- Full in-process round trips (TCP and unix-domain sockets) covered in
tests.
rgrpc 0.0.1.1
- Generic asynchronous unary client on
GenericStub: grpc_client(),
grpc_call(), grpc_poll(), grpc_cancel(), grpc_pending(),
grpc_close(), with deadlines, metadata, and typed status codes.
- Event-loop wakeup via eventfd, exposed through
grpc_fd() for
later::later_fd()-style integration; polling is the fallback, not
the primitive.
rgrpc 0.0.1
- Initial skeleton: system-linked build against the distro gRPC C++
library via
pkg-config, spike shim proving safe create/destroy of
channels, completion queues, and generic servers.