In general, never send responses from custom code. See How do I set a cookie using $response->headers->setCookie() in a form submission handler?
In this case you are sending a redirect response to the client while Drupal builds the real response containing the cookie to the session where the message gets stored. The real response never reaches the client because you've already sent them away.
If you don't have a controller to return the redirect you can use an event subscriber to set the response the Drupal kernel returns. See this code example https://drupal.stackexchange.com/a/274494/47547.
In your case you would set a status message instead of a custom cookie:
/src/EventSubscriber/MymoduleSubscriber.php
<?php
namespace Drupal\mymodule\EventSubscriber;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* mymodule event subscriber.
*/
class MymoduleSubscriber implements EventSubscriberInterface {
/**
* The route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Constructs event subscriber.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match.
*/
public function __construct(RouteMatchInterface $route_match) {
$this->routeMatch = $route_match;
}
/**
* Kernel request event handler.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* The request event.
*/
public function onKernelRequest(RequestEvent $event) {
if (!$event->isMainRequest()) {
return;
}
if (!$this->routeMatch->getRouteName() == 'entity.node.canonical') {
return;
}
$request = $event->getRequest();
if ($this->routeMatch->getRawParameter('node') == '1') {
\Drupal::service('page_cache_kill_switch')->trigger();
if ($some_condition) {
\Drupal::messenger()->addStatus('My message');
$redirect = new RedirectResponse('/foo/bar', 302);
$event->setResponse($redirect);
}
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
KernelEvents::REQUEST => ['onKernelRequest', 31],
];
}
}
mymodule.services.yml
services:
mymodule.event_subscriber:
class: Drupal\mymodule\EventSubscriber\MymoduleSubscriber
arguments: ['@current_route_match']
tags:
- { name: event_subscriber }
hook_entity_view
implementation.hook_entity_view
or something else?