Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[DependencyInjection] env vars are not reset upon kernel.reset #59128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
faizanakram99 opened this issue Dec 7, 2024 · 3 comments
Closed

[DependencyInjection] env vars are not reset upon kernel.reset #59128

faizanakram99 opened this issue Dec 7, 2024 · 3 comments

Comments

@faizanakram99
Copy link
Contributor

faizanakram99 commented Dec 7, 2024

Symfony version(s) affected

7.1.0

Description

#54666 was supposed to reset env vars upon kernel.reset but seems it doesn't work as intended, it probably works for web environments with booted kernels like php-pm or frankenphp worker mode as container is reset for them on each kernel boot but not for messenger workers. Currently there are two issues with it.

  1. EnvVarProcessor is not tagged with kernel.reset
  2. Env vars are cached higher up in stack in Container (service_container) and they are never reset.

See #54666 (comment)

How to reproduce

Reproducer isn't needed, the description is enough to explain the issue.

Possible Solution

First issue can be fixed by adding ->tag('kernel.reset', ['method' => 'reset']) here

Second issue, I'm not sure, maybe we should get rid of services resetter altogether and just reboot kernel (edit: bad idea as pointed out by @stof in following comment). Alternatively, add service_container to services_resetter but just reset envCache (and not other services). It would require another public method other than reset in container class and tagging it with kernel.reset and use that method as "resetMethod". Instead of tagging service_container with kernel.reset, we could simply call that public method from EnvVarProcessor::reset()

Additional Context

Resetting env vars is necessary to be able to run symfony messenger workers for a multi tenant application (single web server multiple databases) where each message is identified with a tenant stamp and depending upon the tenant id, its env var needs are loaded like database_url, filesystem path etc. Also it is similar to web model that way, each message is handled without causing side effects (in isolation).

@stof
Copy link
Member

stof commented Dec 7, 2024

Rebooting the kernel in the messenger consumer is not possible. We would end up with an invalid state as the consumer itself is manager by the container of the kernel. Rebooting a kernel can only be done by code living outside the kernel-managed application, not from inside it. That's precisely why we have the service resetter which is about resetting stateful services for a long-running process.
Resetting the container in such place will not work either, as the worker consumer itself is managed by the container (same reason of not working than for a full reboot, as both a full reboot and a container reset are invalidating all service instances).
IF the service resetter was resetting the container itself (instead of only resetting stateful services), we would not be able to use it to reset state between messenger messages.

Your case of multi-tenancy should be handled using a stateful service from which other services can read that state (not in their constructor but when they need to be used instead) instead of using a custom env var loader to change the values injected in their constructor during instantiation if you want to be compatible with long-running processes that don't re-instantiate services.

I put a big -1 on the proposed "fix" as it would break messenger for all projects.

@faizanakram99
Copy link
Contributor Author

faizanakram99 commented Dec 7, 2024

Resetting the container in such place will not work either, as the worker consumer itself is managed by the container (same reason of not working than for a full reboot, as both a full reboot and a container reset are invalidating all service instances).

Good point, the reset can only reset env vars, it doesn't have to reset all the services.

Your case of multi-tenancy should be handled using a stateful service from which other services can read that state (not in their constructor but when they need to be used instead)

How'll doctrine work in such a scenario, particularly separate database per tenant?
I've edited the OP to make it a bit more clear.

Same goes for things like Filesystem (flysystem), cache, etc.

@faizanakram99
Copy link
Contributor Author

@stof Thank you for pointing the flaw in the previous suggested fix, I've added a PR (#59136) with least distrubtive changes

fabpot added a commit that referenced this issue Jan 17, 2025
…faizanakram99)

This PR was merged into the 7.1 branch.

Discussion
----------

[DependencyInjection] Reset env vars with `kernel.reset`

| Q             | A
| ------------- | ---
| Branch?       | 7.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #59128
| License       | MIT

As mentioned in #59128 and #54666 (comment) (and proceeding comments), EnvVarProcessor isn't tagged with kernel.reset, hence its reset method is never called in ServicesResetter.

Another issue was that env vars are cached high up in stack (in Container class) and even if EnvVarProcessor's cached env vars are cleared, env var loaders still won't be called as env var loaders are called only for missing env keys.

This PR fixes #59128 by adding the missing tag and also clears "env cache" of Container in `EnvVarProcessor::reset()` method (i.e. whenever env vars of EnvVarProcessor are cleared). This is a safe change and won't break existing apps using symfony messenger.

cc `@bendavies`

Commits
-------

4c9e1a4 fix(dependency-injection): reset env vars with kernel.reset
@fabpot fabpot closed this as completed Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants