Repository navigation
Backend: distributed cache and messaging (Redis, RabbitMQ, Kafka, SQS, Pub/Sub) - #6209
shai-almog wants to merge 14 commits into
Conversation
…ons, rate limits and scheduler locks A Redis-protocol client (RESP2, no client jar) behind a KeyValueStore interface, with an in-process store as the default. cn1.kv.url or Spring's spring.data.redis.* selects Redis/Valkey/KeyDB; the store is a server resource opened on first use and closed at shutdown. On top of it: @Cacheable/@CachePut/@CacheEvict woven at build time with a compiled key expression and generated JSON codecs, cn1.session.store=kv, KeyValueRateLimiter, scheduler locks without a database, an injectable KeyValueStore and a health entry. Tested with demo/kvcheck on the JVM and ParparVM against podman Redis 7, Valkey 8 and an ACL-protected Redis, and BackendBeansTest with CN1_TEST_REDIS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ox, retry and dead letters MessageTemplate and @MessageListener (with the Spring-named @KafkaListener, @RabbitListener and @JmsListener aliases) over a pluggable MessageTransport. The build discovers listeners, generates each subscription with its typed decode, and registers only the transports application.properties names. Without a broker URL a server with a database uses the db: transport (a queue table claimed with SKIP LOCKED on PostgreSQL), otherwise memory:. A send inside a transaction goes through an outbox relayed after commit. Failed deliveries retry with backoff and then land in <destination>.dlq. First cut of the Redis Streams transport, tested in the next change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
redis:// sends with XADD and consumes through XREADGROUP consumer groups, reclaiming abandoned messages with XPENDING/XCLAIM after the lease and holding retries in a sorted set. amqp:// is a client for RabbitMQ written on Tcp: durable queues, persistent publishes with publisher confirms, one consuming connection per subscription with a prefetch equal to its concurrency, retries parked in TTL queues that dead-letter back, and reconnection after the broker restarts. Fixes found on the way: - the outbox did database work inside the commit callback, which the transaction manager refuses; the outbox thread now relays, sending before it deletes so a crash re-sends instead of losing the message, and a sweep claims a row before sending it - a module of message listeners alone produced no server - the consumer loop logged a broker outage once a second Tested on the JVM and natively against Redis 7, Valkey and RabbitMQ 3.13 in podman, and through the generated wiring for every transport. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Kafka client written on the backend's own Tcp layer: produce with acks=all and Kafka's murmur2 partitioner, consumer groups with range assignment computed from every member's subscription, per-partition ordering, offsets committed after the handler returns, non-blocking retry topics and a dead-letter topic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both over HTTP with no vendor SDK: SQS through the backend's SigV4 signer, with retries as visibility changes counted by SQS's receive count; Pub/Sub through a service-account key or the metadata server (or the emulator), one subscription per group, retries as ack-deadline changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Kafka: advance the fetch offset past control and empty batches so a partition never stalls on one. - Cache keys: refuse identity-keyed parameters (arrays, objects without their own toString) at build time; a null key part no longer collides with the text "null". - Transports: a RuntimeException in a poll, ack or outbox relay no longer kills the consumer thread. - cn1.messaging.transports names the transports to compile in when the broker URL is only known at run time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cloudflare Preview
|
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
…ache # Conflicts: # docs/developer-guide/languagetool-accept.txt
✅ ByteCodeTranslator Quality ReportTest & Coverage
Benchmark Results
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 195 screenshots: 195 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
|
Compared 231 screenshots: 231 matched. |
|
Compared 210 screenshots: 210 matched. Benchmark ResultsDetailed Performance Metrics
ParparVM vs HotSpot (JDK 25): Windows x64Runner CPU: AMD64 Family 25 Model 1 Stepping 1, AuthenticAMD (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
The compiled-tests build refused key "#id" on Catalog.photo. The guide's example and wording now lead with #p0 and say when a name works. Initializr template resynced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ache # Conflicts: # scripts/initializr/common/src/main/resources/savor-modules.zip
|
Compared 210 screenshots: 210 matched. Benchmark ResultsDetailed Performance Metrics
|
The Initializr template builds against the released framework, which has no backend cache annotations yet, so the shipped Savor failed to compile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ache # Conflicts: # docs/developer-guide/languagetool-accept.txt
|
Compared 192 screenshots: 192 matched. Benchmark Results
Detailed Performance Metrics
|
|
Compared 210 screenshots: 210 matched. ParparVM vs HotSpot (JDK 25): Linux x64Runner CPU: AMD EPYC 9V45 96-Core Processor (baseline 1 performance regression:
Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
A change that moves performance ON PURPOSE records the new baseline in Result: performance regression |
|
Compared 210 screenshots: 210 matched. ParparVM vs HotSpot (JDK 25): Linux arm64Runner CPU: Neoverse-N2 (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
|
Compared 210 screenshots: 210 matched. Benchmark ResultsDetailed Performance Metrics
ParparVM vs HotSpot (JDK 25): Windows arm64Runner CPU: ARMv8 (64-bit) Family 8 Model D49 Revision 0, MICROSOFT CORPORATION (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
|
Compared 253 screenshots: 253 matched. |
|
Compared 196 screenshots: 196 matched. Benchmark Results
Detailed Performance Metrics
ParparVM vs HotSpot (JDK 25): macOS arm64Runner CPU: Apple M1 (Virtual) (baseline 1 improvement past the baseline (not a failure; rebaseline to lock it in):
Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
A change that moves performance ON PURPOSE records the new baseline in Result: no regression (improved past the baseline: consider rebaselining) |
|
Compared 193 screenshots: 193 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 188 screenshots: 188 matched. |
|
Compared 193 screenshots: 193 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
Adds a shared key/value store and messaging to the backend, so a server can scale out past one instance.
cn1.kv.url, or Spring'sspring.data.redis.*. It backs@Cacheable/@CachePut/@CacheEvict, sessions, rate limits and@Scheduledlocks.MessageTemplateplus@MessageListener.@KafkaListener,@RabbitListenerand@JmsListenerare also accepted as written..dlqdead-letter destination.memory:,db:(the default with a database), Redis Streams, AMQP 0-9-1, Kafka, SQS and Pub/Sub.Backend-Messaging.asciidoc), and Savor caches menu photos with@Cacheable.Tested with the
msgcheckharness against real brokers in podman: Kafka, RabbitMQ, Redis, ElasticMQ and the Pub/Sub emulator, on both the JVM and ParparVM.🤖 Generated with Claude Code