fix: preserve env placeholders in serialized message attributes#671
Merged
Conversation
Attributes carrying %env()% placeholders were stored in the container as serialize() blobs; Symfony rewrote the placeholder inside the blob during container compilation, breaking the serialized length prefix so unserialize() returned false and the consumer/handler could not be built. Build attribute definitions from DefinedObject::getDefinition() (structured class + arguments) instead of serialize(), so each placeholder is a normal container argument Symfony resolves correctly. Fixes #669
getDefinition() omitted finalFailureStrategy and placed connectionReference in its slot, so reconstructing the attribute via new RabbitConsumer(...) passed a string where the FinalFailureStrategy enum is required. Harmless while attributes were stored via serialize(), but now that DefinedObject attributes are rebuilt from getDefinition() it must match the constructor.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why is this change proposed?
Since 1.313.0, consuming messages in a Symfony application fails with
DefinitionHelper::unserializeSerializedObject(): Return value must be of type object, false returnedwhenever an attribute contains an environment placeholder — e.g.#[KafkaConsumer(topics: 'orders.%env(SUFFIX)%')]or#[Asynchronous(asynchronousExecution: [new ErrorChannel('%env(ERROR_CHANNEL)%')])].Ecotone stored such attributes as PHP-
serialize()d strings in the container. Symfony then rewrites the%...%placeholder inside that string during container compilation, which changes the string's byte length but not the serialized length prefix (s:NN:"…"), sounserialize()returnsfalseand the consumer/handler can never be built. It only reproduces under a real Symfony container (Symfony resolves%...%in service arguments). Fixes #669.Description of Changes
DefinitionHelpernow builds attribute container definitions fromDefinedObject::getDefinition()(a structured class + arguments) instead ofserialize(), so each placeholder-bearing string is a normal container argument that Symfony resolves correctly — no length-prefix corruption, and the environment value is still applied.#[Asynchronous],#[ErrorChannel],#[DelayedRetry],#[WithoutMessageCollector],#[WithoutDatabaseTransaction]now implementDefinedObject(#[KafkaConsumer]already did). AllAsynchronousEndpointAttributeelements must beDefinedObjectbecause#[Asynchronous]now exposesasynchronousExecutionstructurally.buildAttributeDefinitionFromInstance+resolvePotentialComplexAttribute); the genericbuildDefinitionFromInstanceis left as-is to avoid affecting service configurations.ecotone/kafka+ext-rdkafkato the Symfony packagerequire-dev.Usage examples
Use cases
orders.stagingvsorders.production) driven by env vars.%env(...)%in a Symfony app.Flow
sequenceDiagram participant App as Symfony container (compile) participant Runtime Note over App: Before — serialize() blob: s:28:"orders.%env(SUFFIX)%" App->>Runtime: %env% resolved inside blob -> s:28:"orders.production" (length mismatch) -> unserialize() = false Note over App: After — structured Definition arg: "orders.%env(SUFFIX)%" App->>Runtime: %env% resolved as a whole argument -> new KafkaConsumer('orders.production')Pull Request Contribution Terms