Sending x-message-ttl to RabbitMQ through Symfony Messenger - symfony

How can I define x-message-ttl for a RabbitMQ queue with Symfony Messenger?
I see it is used with the DelayStamp, but I don't want to setup a Delay. I would simply like messages to drop if they are not handled within a certain time frame. I don't see it referenced anywhere else in the source code.
The only documentation I can find is for the old method of using the OldSound RabbitMq package.

I figured it out indirectly through this PR.
messenger.yaml
framework:
messenger:
transports:
mywork:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
exchange:
name: mywork
type: direct
queues:
mywork:
arguments:
x-message-ttl: 60000

Related

symfony 5 how to mock/replace service in container

I want to make a mock for some class in my functional test. Let's say I want to mock some custom command bus realization.
First of all I need to register that service as a public in the services_test.yaml:
services:
_defaults:
public: true
App\CommandBus: ~
but still even if I did so I'm getting error service is already initialized, you cannot replace it when doing something like:
$commandBus = $this->createMock(CommandBus::class);
$commandBus->expects(self::once())
->method('dispatch')
->with($data)
->willReturn($response);
self::$container->set(CommandBus::class, $commandBus);
So how can I easily mock some object and insert mocked version to the container???
Probably I can make some wrapper for tests link it with interface in services_test.yaml, and add a methods like setExpectiotion which will chekc if expectation set and if so instead of running command return it. But it's extra work and it's taking a lot of time to design such a class for each service I want to mock.
Is there any other way to mock some service?? Thanks in advice!
I assume your command bus is using an asynchronous transport type. If you wish you can solve this problem using sync transport for tests instead. You don't need to mock it in this case, because if you will mock command bus, you will test mock instead of the whole process.
Let's create a new config in config/packages/test/messenger.yaml
framework:
messenger:
transports:
command_bus: 'sync://'
Then enable the functional test without worrying about the consumer.
If you want to debug container for tests, you can check it using command
./bin/console debug:container -e test
Please let me know if that solves your problem.

How to turn off logging for symfony messenger component

I have a Symfony website that's something inbetween an actual implementation and staging (it's used by a special client of mine). The logging is kept ON on that server because that helps when things go wrong from time to time (and they often go wrong in non-obvious, non-error/exception ways). Most of the logged lines are by Doctrine - executed queries, which is very useful to me, but I do manually disable logging for SOME of the huge, repetitive and well-tested operations that spam hundreds of queries, to keep the log easier to navigate, if needed.
My question is: How do I disable logging done from inside of the Symfony messenger component? Specifically, logging done by the doctrine transport (which I use), which spams my log with following lines every second (multiplied by the number of supervisord processes that I run):
[2020-08-24 14:19:25] doctrine.DEBUG: "START TRANSACTION" [] []
[2020-08-24 14:19:25] doctrine.DEBUG: SELECT m.* FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC LIMIT 1 FOR UPDATE ["2020-08-24 13:19:25","2020-08-24 14:19:25","default"] []
[2020-08-24 14:19:25] doctrine.DEBUG: "COMMIT" [] []
Since these messages are generated by doctrine, I can't filter them out through logging channels - because that would disable ALL doctrine log messages, and that's not what I want. I also don't want to raise the logging level to something higher than DEBUG. I want to remove ONLY these specific messages from the log.
I just wanted to tackle this issue and I found that most of the spam can be avoided by using a fingers_crossed monolog handler instead of the default one. This quick solution avoid to fully disable Doctrine logs.
In packages/dev/monolog.yaml, replace
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
by :
main:
type: fingers_crossed
action_level: info
handler: nested
channels: ["!event"]
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
You have many options.
Exclude messenger log info:
Disable Symfony Messenger log info
Log your message in a different file:
You can log Messages to different Files. Like it's described in this part of the Symfony documentation.
Configure the logger level:
You can configure your logger entry with level info, that can help you to have a log file corresponding to what you want to see. For example, you can use the ERROR level to just have errors in your Message.
Check the documentation below Loggin component.
Create your own channel:
You can create your own channel and subscribe to it, that excludes doctrine. Creating your own channel
Just search what you want with grep:
If you want to filter more what you want to see when you read the log file, you can use grep like:
tail path/to/my/logfile.txt | grep 'what I want to see'
That permits us to avoid useless lines. grep man page
The straight solution was when running the consumer use the flag --no-debug
php bin/console messenger:consume async_email_handler --no-debug
This will stop writing the doctrine lines in the .log file

Using senders independent in Symfony messenger component

I'm using Symfony 4.2 and have one message to dispatch via messenger component which is a notification that should be sent via a few channels (for example SMS and email). I'm wondering how to make these senders independent (for example first channel fails and throw an exception) - how to make a try to send independent via the second sender? Currently, when one of the senders in the chain fails the rest can't make a try of delivering notification.
Catching exception on the sender level seems not to be a good solution, because returning envelop causes that it will be stamped as sent what is not true.
I've started to make message per channel to keep sentStamp convention, but It seems that should be one message and few channels listening for one message (even configuration indicates to that with senders keyword):
routing:
'App\Messenger\Command\Notification\SendSomeInformation':
senders:
- App\Messenger\Sender\Notification\EmailSender
- App\Messenger\Sender\Notification\SmsSender
There is some good approach for such problem?
One possibility would be to configure two different transports, and assign each handler to different transports, so if one of them fails and dequeues the message, the other can still have a chance to run.
# config/packages/messenger.yaml
transports:
async1:
# dsn
async2:
# dsn
...
routing:
'App\Messenger\Command\Notification\SendSomeInformation': [async1, async2]
Restricting handlers to transports can be done either in code or config, choose what works better for you.
In config:
# config/services.yaml
App\Messenger\Sender\Notification\SmsSender:
tags:
- { name: 'messenger.message_handler', from_transport: 'async1'}

Losing connection to Redis Service

We have a Symfony application deployed on a Swisscom provided Cloudfoundry Instance. Additionally we're using a Redis Service provided by Swisscom for caching.
It happened now two times that we're getting a timeout for the Redis Connection which causes our Application to fail:
Redis connection failed (connect() failed: Connection timed out): redis://password#domain.service.consul:47133
Some technical information:
symfony/symfony (v3.3.9)
predis/predis (v1.1.1)
cf version 6.32.0+0191c33d9.2017-09-26
config.ymllooks like that for Caching:
framework:
cache:
system: cache.adapter.apcu
default_redis_provider: redis://%redis_password%#%redis_host%:%redis_port%
pools:
redis_pool:
adapter: cache.adapter.redis
public: true
default_lifetime: 0
provider: cache.default_redis_provider
and is used as a Service as defined here:
tag_aware_cache:
class: Symfony\Component\Cache\Adapter\TagAwareAdapter
arguments: [ '#redis_pool' ]
To my understanding we aren't using any persistent connection to Redis and it's usually working fine.
The only solution I found so far to get the application back in stable and running state is to re-deploy the whole application which isn't really a good solution.
Especially I don't understand what could be the root cause.
How could I check this on my own and is Swisscom sure that Redis Service itself runs fully stable?
You can access the service directly when using 'cf ssh' to your app. The complete process on how to access your service using 'cf ssh' is described in Swisscoms documentation: https://docs.developer.swisscom.com/devguide/deploy-apps/ssh-apps.html
You're app should be able to handle connectivity issues by itself. Usually a simple retry keeps the app from crashing.

Symfony MonologBundle: Use a sentry processor inside Symfony's MonologBundle

I've configured a Sentry handler for Monolog via config.yml. Now I need to filter out some data from the log data. The data is added in sentry's raven_handler. Thus I need to use a Sentry processor to filter it out. Monolog processors are working before the log goes to the sentry.
I do not find a way to pass a Sentry processor via Monolog's .yml configuration.
Do you have any suggestions?

Resources