Skip to content

fix: restore Jackson 2.x property order in RqueueRedisSerializer to prevent stale processing-queue entries after 3.x → 4.x upgrade#300

Merged
sonus21 merged 3 commits into
sonus21:masterfrom
roxid:fix/v3-compatibility
May 18, 2026
Merged

Conversation

@roxid
Copy link
Copy Markdown
Contributor

@roxid roxid commented May 16, 2026

Description

RQueue 4.x switched to Jackson 3.x, which defaults to alphabetical property ordering. RQueue 3.x used Jackson 2.x with declaration order. The same RqueueMessage therefore serialises to different bytes depending on which version enqueued it, causing byte-exact ZSCORE/ZREM lookups in parkForRetry and ack to silently miss — leaving 3.x messages stranded in the processing queue and re-delivered indefinitely via the visibility timeout.

Fixes #299

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • This change requires a documentation update

How Has This Been Tested?

  • Integration Test: Inserts a genuine Jackson 2.x-serialized message directly into the processing ZSET via a passthrough template, then calls parkForRetry and ack using the live serializer. Using different serializers for write and lookup is intentional — if both sides used the same serializer the test would trivially pass regardless of whether the fix is present.

Test Configuration:

  • Spring Version: 7.0.3
  • Spring Boot Version: 4.0.1
  • Redis Driver Version: Lettuce 7.2.1.RELEASE (embedded Redis 1.4.3)

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

…revent stale processing-queue entries after 3.x → 4.x upgrade
Comment thread rqueue-core/build.gradle
api "org.apache.commons:commons-collections4:${apacheCommonCollectionVerion}"
// https://mvnrepository.com/artifact/io.micrometer/micrometer-core
api "io.micrometer:micrometer-core:${microMeterVersion}"
testImplementation "com.fasterxml.jackson.core:jackson-databind:2.21.2"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Can you please bump the version in root to RC10?

@roxid
Copy link
Copy Markdown
Contributor Author

roxid commented May 16, 2026

Note that any 4.x deployment that has messages currently sitting in the processing queue should drain that queue before deploying this fix. move_expired_message.lua preserves raw bytes verbatim when rescuing messages, so alphabetical-order bytes written by an unpatched 4.x instance are never corrected by the rescue path — the ZSCORE miss will recur on every re-delivery, creating the same infinite loop as the original bug, just in reverse.

@sonus21
Copy link
Copy Markdown
Owner

sonus21 commented May 16, 2026

Can we add this as a prop?

@roxid
Copy link
Copy Markdown
Contributor Author

roxid commented May 16, 2026

A property based solution seems to get rather messy. I'll try to implement a more robust solution (e.g. making the processing-queue lookups in move_message_zset.lua, move_message_list.lua, and ack using an ID-based fallback).

@sonus21
Copy link
Copy Markdown
Owner

sonus21 commented May 16, 2026

A property based solution seems to get rather messy. I'll try to implement a more robust solution (e.g. making the processing-queue lookups in move_message_zset.lua, move_message_list.lua, and ack using an ID-based fallback).

This would be quick change right? We can add a property rqueue.serialization.property.order=ALPHABETICALLY|DEFAULT.

@roxid
Copy link
Copy Markdown
Contributor Author

roxid commented May 16, 2026

DEFAULT (declaration order, matching Jackson 2.x / RQueue 3.x) as the out-of-the-box value is intended? Meaning projects already using 4.x are required to explicitly set ALPHABETICALLY.

Maybe using ALPHABETICALLY as the default value, naming the old declaration order LEGACY and adding documentation to the migration guide is a more future proof approach here.

@sonus21
Copy link
Copy Markdown
Owner

sonus21 commented May 17, 2026

DEFAULT (declaration order, matching Jackson 2.x / RQueue 3.x) as the out-of-the-box value is intended? Meaning projects already using 4.x are required to explicitly set ALPHABETICALLY.

Maybe using ALPHABETICALLY as the default value, naming the old declaration order LEGACY and adding documentation to the migration guide is a more future proof approach here.

Yeah this make sense, Also we can take a approach used by Lombok. Serialization format jackson2.x or jackson3+. Both of these would work, but adding legacy does not tell us why this is called legacy.

…N field ordering

Introduces RqueueRedisSerializer.PropertyOrder enum (ALPHABETICAL | DECLARATION)
and wires it via rqueue.serialization.property.order (default: ALPHABETICAL).

ALPHABETICAL uses Jackson 3.x alphabetical ordering, the native default for
RQueue 4.x deployments. No configuration change required for new installs.

DECLARATION uses declaration order, matching the Jackson 2.x behaviour of
RQueue 3.x. Set this when upgrading from 3.x with messages still in Redis
queues, as switching while messages are in-flight causes unexpected retries.

The setting is applied in RqueueListenerBaseConfig before any Redis template is
created (overriding RedisUtils providers when DECLARATION is requested), and
flows through RqueueConfig to RqueueInternalPubSubChannel so all serialiser
instances in the application use the same order.

Docs: configuration.md and migrations.md updated with property description,
accepted values, and the 3.x → 4.x migration warning.

Assisted-By: Claude Sonnet 4.6
@roxid
Copy link
Copy Markdown
Contributor Author

roxid commented May 17, 2026

Both of these would work, but adding legacy does not tell us why this is called legacy.

You're right, naming should be consistent and describe the actual behaviour.

Added rqueue.serialization.property.order=ALPHABETICAL|DECLARATION to control JSON property ordering. ALPHABETICAL (Jackson 3.x native) is the default for new 4.x deployments. Set DECLARATION when upgrading from 3.x with messages still present in Redis queues.

@sonus21 sonus21 merged commit f4a3715 into sonus21:master May 18, 2026
9 of 10 checks passed
@roxid roxid deleted the fix/v3-compatibility branch May 18, 2026 07:18
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.

Messages enqueued by RQueue 3.x are repeatedly re-delivered after upgrading to 4.x

2 participants