Build a resilient AI agent with Symfony Messenger and Redis. Learn async workflows to boost performance, scalability, and fault tolerance.Build a resilient AI agent with Symfony Messenger and Redis. Learn async workflows to boost performance, scalability, and fault tolerance.

Your AI Agent Is Too Slow—Here’s How to Fix It

In our previous article, we developed a basic AI agent that performed well enough when run from the console. However, this simple, linear approach has significant limitations in terms of speed and resource efficiency.

Network connections to remote services and data retrieval from external servers are inherently time-consuming operations. This is due to the overhead of establishing a connection, transmitting data over the Internet, and closing the session — all before considering potential server load from other requests. What’s more, a critical component — such as the mailbox servers, the LLM model servers, or the outbound email servers — might be temporarily unavailable.

By adopting an asynchronous approach for interacting with each external resource, we can dramatically accelerate the overall system. This not only boosts performance but also enhances system resilience, minimizing downtime when external resources are temporarily unavailable. This article will show you how to leverage asynchronous programming to create a faster, more robust AI agent.

Building a Resilient AI Agent: Handling Service Disruptions Asynchronously

Imagine a scenario where the LLM model server becomes temporarily unavailable. In a robust, asynchronous system, this isn’t a showstopper. Instead of halting all operations, we can simply continue to retrieve emails, queue them up for analysis, and then, once the LLM server is back online, independently send the queued data for processing without disrupting other business logic.

For the sake of this simple example, we won’t delve into data persistence or a comprehensive error-handling strategy for network issues. However, I will demonstrate how you can easily decouple your application components by moving core modules to an asynchronous operating mode.

A perfect tool for this is the Symfony Messenger Component. It is an outstanding solution for building asynchronous workflows and facilitates seamless communication between different parts of a single application, as well as between entirely separate applications.

To install the Symfony Messenger Component using Composer, you just need to run a single command in your project’s root directory.

\

composer require symfony/messenger  

Flexible Transports: Powering Symfony Messenger

The Symfony Messenger Component is incredibly versatile, supporting a wide range of transports such as AMQP, Doctrine, Redis, Amazon SQS, and many more. This flexibility allows you to select the best transport for each specific task within your application.

Each transport can be configured for both synchronous and asynchronous operations. You can also assign different priorities, set message limits, and configure other useful parameters that are essential for managing high-load production environments. This fine-grained control greatly simplifies the deployment of mission-critical applications.

A key advantage of the Messenger component is its transport-agnostic nature. This means you can easily switch between transports as your needs evolve. For example, you could start with Redis, transition to AMQP later, and then, for a super-high-traffic production environment, seamlessly switch to a cloud-based solution like Amazon SQS. This freedom of choice ensures your architecture can scale and adapt over time.

For our project, we will be using Redis. This transport is a highly efficient choice for message queuing, leveraging Redis Streams to handle messages reliably. This transport requires the Redis PHP extension (php-redis, version 4.3 or higher) and a running Redis server (5.0 or higher).

To install the necessary components, simply run the following command in your terminal:

\

composer require symfony/redis-messenger  

Configuring the Redis Transport DSN

Define environment variable named MESSENGERTRANSPORTDSN

\

MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages  

Let’s break down this DSN:

redis://: The protocol specifying we’re connecting to a Redis service.

localhost: The hostname of your Redis server. Replace this with the server’s IP address or hostname if it’s not running locally.

6379: The default port for Redis. Change this if your server uses a different port.

/messages: This is the name of the Redis stream (or queue) where messages will be stored. This allows you to have multiple, separate queues on the same Redis server.

By defining this variable, your Symfony Messenger configuration can dynamically pull the connection details without hardcoding them, making your application more portable and secure.

Boost Performance and Decouple Components with a CQRS-Based Bus Architecture

Data buses are built on top of the transport layer. They not only structure the flow of messages but also allow for additional pre- and post-processing via middleware as a message enters the bus.

For our project, I propose creating and maintaining three primary data buses right from the start. This approach is based on the CQRS (Command Query Responsibility Segregation) pattern, which we might explore in more detail in future articles.

\

  1. Command Bus

A command is a message that tells the application to perform a specific action that changes its state. It represents a single, imperative instruction.

Main purpose is to change data or trigger a business process. It’s an instruction to “do this” (e.g., CreateOrder, ChangeProductName).

A command should have only one handler that executes the logic and doesn’t return a value. Its success or failure is handled through exceptions.

\

  1. Query Bus

A query is a message that asks for data without changing the application’s state.

Main purpose is to retrieve data from the application. It’s a request to “get me this” (e.g., GetProductDetails, ListAllUsers).

A query should have only one handler that fetches the required data and query handler always returns the requested data.

\

  1. Event Bus

An event is a message that announces that something noteworthy has already happened in the application. It is a record of a past action.

Main purpose is to notify other parts of the system about a change so they can react to it. It’s a statement that “this happened” (e.g., UserCreated, OrderShipped).

An event can have zero, one, or many listeners or subscribers. Events are often handled asynchronously to decouple different parts of the system, which is a key benefit of this approach.

Messenger Component Configuration: A Step-by-Step Guide

Here is the complete config/packages/messenger.yaml configuration to set up your message buses, transports, and routing, including support for the Symfony Notifier component.

\

framework:     messenger:         default_bus: core.command.bus         buses:             core.command.bus:                 default_middleware:                     enabled: true                     allow_no_handlers: false                     allow_no_senders: false             core.query.bus:                 default_middleware:                     enabled: true                     allow_no_handlers: true                     allow_no_senders: true             core.event.bus:                 default_middleware:                     enabled: true                     allow_no_handlers: true                     allow_no_senders: true          transports:             main.transport:                 dsn: '%env(MESSENGER_TRANSPORT_DSN)%'          routing:             '*': [main.transport] 

This setup enables your AI agent to handle tasks asynchronously, which is crucial for building a responsive and resilient application.

Building an Asynchronous Workflow: Summarizing Emails with an AI Agent

Now, let’s create the core asynchronous process that will interact with our LLM. This crucial step allows our application to offload a time-consuming task — communicating with an external API — without blocking the main application thread. This makes our AI agent more efficient and resilient.

The workflow will be as follows: a message is dispatched to the bus, which will asynchronously connect to the LLM model. It will send the retrieved emails for summarization and, upon a successful response, will initiate a new asynchronous process to send a notification via our chosen channel.

To achieve this, we’ll need two key components: the AIAgentSummarizeMessage and its corresponding handler, AIAgentSummarizeMessageHandler.

The AIAgentSummarizeMessage Class

This class acts as a data transfer object (DTO). It encapsulates all the necessary information for our LLM summarization task, ensuring the message is self-contained and easy to handle.

\

namespace App\Message\Command;  use App\DTO\DataCollection;  readonly class AIAgentSummarizeMessage {     public function __construct(         private DataCollection $dataCollection,         private string $prompt,     )     {     }      public function getDataCollection(): DataCollection     {         return $this->dataCollection;     }      public function getPrompt(): string     {         return $this->prompt;     } } 

$dataCollection: This property holds the collection of email objects or other data that our AI agent needs to analyze.

$prompt: This string will contain the specific instructions for the LLM, guiding it on how to summarize the provided data.

The AIAgentSummarizeMessageHandler Class

The handler is a dedicated class that listens for and processes AIAgentSummarizeMessage objects. In Symfony Messenger, the core logic is placed inside a single public method named __invoke. This method is automatically called whenever a message of the correct type appears in the bus.

\

namespace App\Handler\Command;  use App\DTO\MailMessage; use App\Message\Command\AIAgentSummarizeMessage; use App\Message\Command\NotifySummarizedMessage; use App\Service\AIAgentService; use App\Service\AIProvider\GeminiAIAgentService; use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Notifier\Notification\Notification;  #[AsMessageHandler(bus: 'core.command.bus', fromTransport: 'main.transport')] readonly class AIAgentSummarizeMessageHandler {     public function __construct(         private AIAgentService $aiAgentService,         private GeminiAIAgentService $geminiAIAgentService,         protected MessageBusInterface $messageBus     ){     }      public function __invoke(AIAgentSummarizeMessage $message): void     {         $result = $this->aiAgentService->action($this->geminiAIAgentService, $message->getDataCollection(), $message->getPrompt());          if (!is_null($result)) {             $this->messageBus->dispatch(                 new Envelope(                     new NotifySummarizedMessage(                         new MailMessage(                             'Summary message',                             null,                             '[email protected]',                             $result,                             null                         ),                         Notification::IMPORTANCE_MEDIUM                     )                 )             );         }     } } 

Finalizing the Workflow: Creating the Asynchronous Notification Process

To complete our resilient workflow, we’ll create a second message and handler pair. This ensures that sending a notification is a completely separate and asynchronous process from the LLM summarization. This decoupling is a cornerstone of a robust system; if your email server is temporarily unavailable, the summarization process will still complete successfully, and the notification can be retried later without affecting other services.

For this step, we’ll need a new message, NotifySummarizedMessage, and its dedicated handler, NotifySummarizedMessageHandler.

The NotifySummarizedMessage Class

This message will carry all the information needed to send a notification.

\

namespace App\Message\Command;  use App\DTO\MailMessage; use Symfony\Component\Notifier\Notification\Notification;  readonly class NotifySummarizedMessage {     public function __construct(         private MailMessage $notification,         private string $importance = Notification::IMPORTANCE_MEDIUM     )     {     }      public function getNotification(): MailMessage     {         return $this->notification;     }     public function getImportance(): string     {         return $this->importance;     } } 

$notification: This property holds the MailMessage object. It contains the email’s subject, body, and other relevant details.

$importance: This string allows you to specify a priority (e.g., ‘high’, ‘urgent’) to control which Notifier channel is used for delivery. This is highly useful for sending different types of notifications via different services (e.g., urgent alerts via SMS or Messengers, regular updates via email).

The NotifySummarizedMessageHandler Class

This handler will listen for NotifySummarizedMessage objects on the bus. Its sole purpose is to use the Symfony Notifier component to send the message to the specified channel, completing our asynchronous chain.

Just like our previous handler, it will contain a single __invoke method that is automatically triggered by the Messenger component.

\

namespace App\Handler\Command;  use App\Message\Command\NotifySummarizedMessage; use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Notifier\Notification\Notification; use Symfony\Component\Notifier\NotifierInterface; use Symfony\Component\Notifier\Recipient\Recipient;  #[AsMessageHandler(bus: 'core.command.bus', fromTransport: 'main.transport')] readonly class NotifySummarizedMessageHandler {     public function __construct(         private NotifierInterface $notifier     )     {     }      public function __invoke(NotifySummarizedMessage $message){          $notification = (new Notification(             $message->getNotification()->getSubject()))             ->content($message->getNotification()->getBody())             ->importance($message->getImportance());          $recipient = new Recipient(             $message->getNotification()->getTo()         );          $this->notifier->send($notification, $recipient);      } } 

\ By completing this step, our AI agent now has a fully decoupled, resilient, and scalable workflow. The LLM summarization and the notification processes are completely independent, ensuring that your system can handle failures gracefully and continue to perform under load.

Configuring Message Routing for Your AI Agent

While our current setup uses a single asynchronous transport, it’s a best practice to explicitly define routing rules for each message type. This approach makes your application’s message flow clear, maintainable, and easily scalable for future growth.

By configuring these rules in config/packages/messenger.yaml, we’re explicitly telling Symfony where to send each message. This prepares our system for a more complex architecture with different transports for various tasks, priorities, or external services.

\

framework:     messenger:         default_bus: core.command.bus         ...         routing:             '*': [main.transport]              App\Message\Command\AIAgentSummarizeMessage: [main.transport]             App\Message\Command\NotifySummarizedMessage: [main.transport] 

By adding these two lines, we’ve clearly defined the flow for our entire asynchronous workflow.

Updating the Summarize Command: Dispatching Messages to the Bus

Now that our asynchronous workflow is in place, we need to update our SummarizeCommand. Its new purpose is no longer to perform the time-consuming tasks itself, but to act as a lightweight dispatcher.

\

declare(strict_types=1);  namespace App\Command;  use App\Message\Command\AIAgentSummarizeMessage; use App\Service\ImapMailService; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface;  #[AsCommand(name: 'app:summarize', description: 'Summarize Command')] class SummarizeCommand extends Command {     public function __construct(         private readonly ImapMailService $imapMailService,         private readonly MessageBusInterface $messageBus,     ){         parent::__construct();     }     protected function execute(InputInterface $input, OutputInterface $output): int     {          $emailCollection = $this->imapMailService->fetchEmails(2);          $this->messageBus->dispatch(             new Envelope(                 new AIAgentSummarizeMessage(                     $emailCollection,                     'I have emails. Please summarize them into a concise overview (100-150 words) focusing on key decisions, action items, and deadlines. Use bullet points to organize the summary by email or theme, whichever is clearer. Here’s the email content:'                 )             )         );          return Command::SUCCESS;     } } 

This change is fundamental to our non-blocking approach. The command will now finish its job instantly, freeing up the terminal while the long-running LLM and notification processes run silently in the background.

Putting It All Together: Launching Your Asynchronous AI Agent

We’ve successfully built a complete asynchronous workflow for your AI agent. Every component — from retrieving emails to summarizing them with an LLM and sending a notification — is now decoupled and runs in the background.

Starting the Messenger Consumer 🚀

First, open a new terminal window and run the following command. This command starts the consumer, a dedicated process that will continuously listen to the Redis stream for new messages and process them in the background.

\

./bin/console messenger:consume --all -vv  

This command will start the consumer, and you should see a message indicating it’s now listening for new messages (-vv). Leave this terminal window running, as it will handle all the background tasks.

Initiating the Mailbox Process 📬

With the consumer running, open a second terminal and execute command to initiate the main business logic. This is the command that triggers the entire asynchronous workflow by dispatching the first message (e.g., AIAgentSummarizeMessage) to the message bus.

\

./bin/console app:summarize  

Watch the Magic Happen ✨

Once you run this, you will see a message confirming the dispatch. Simultaneously, in the first terminal, the consumer will immediately pick up the message from the queue and begin processing it, starting the LLM summarization and subsequent notification steps. This is the asynchronous approach in action.

This is the entire asynchronous chain working seamlessly:

  1. Your command dispatches a message and exits.
  2. The consumer listens to the queue, retrieves the message, and processes the LLM request in the background.
  3. Upon success, it dispatches a new notification message.
  4. The consumer then picks up and processes the new message to send the notification.

Conclusion

We have successfully built a resilient, high-performance AI agent that can handle complex, time-consuming tasks without ever blocking the main application.

In our upcoming articles, we will take this project to the next level. I’ll show you how to automate the entire process by:

Scheduling Mailbox Polling: We’ll set up a system to automatically check mailboxes at regular intervals.

Containerizing with Docker: We’ll package our entire application into a Docker container to ensure a consistent and portable environment.

Deploying with a Process Manager: We’ll explore two different methods for running our consumers in a production environment:

  • Using a dedicated process manager like Supervisor to manage our workers.
  • Running the consumers as a standalone, multi-process worker for optimal performance.

Each of these approaches has its own set of advantages and trade-offs, which we’ll thoroughly examine to help you choose the best deployment strategy for your needs.

Stay tuned — and let’s keep the conversation going.

Market Opportunity
Brainedge Logo
Brainedge Price(LEARN)
$0.00932
$0.00932$0.00932
-1.68%
USD
Brainedge (LEARN) Live Price Chart
Disclaimer: The articles reposted on this site are sourced from public platforms and are provided for informational purposes only. They do not necessarily reflect the views of MEXC. All rights remain with the original authors. If you believe any content infringes on third-party rights, please contact [email protected] for removal. MEXC makes no guarantees regarding the accuracy, completeness, or timeliness of the content and is not responsible for any actions taken based on the information provided. The content does not constitute financial, legal, or other professional advice, nor should it be considered a recommendation or endorsement by MEXC.

You May Also Like

Sui Mainnet Recovers After 6-Hour Network Stall: No Funds at Risk

Sui Mainnet Recovers After 6-Hour Network Stall: No Funds at Risk

On January 14, 2026, Sui Mainnet faced a significant disruption, leaving the network stalled for roughly six hours. The incident was caused by an internal divergence
Share
Tronweekly2026/01/17 09:30
Will There Be A ’28 Years Later 3’ After ‘The Bone Temple’? Here’s The Good News

Will There Be A ’28 Years Later 3’ After ‘The Bone Temple’? Here’s The Good News

The post Will There Be A ’28 Years Later 3’ After ‘The Bone Temple’? Here’s The Good News appeared on BitcoinEthereumNews.com. Chi Lewis-Parry and Ralph Fiennes
Share
BitcoinEthereumNews2026/01/17 09:21
Urgent: Coinbase CEO Pushes for Crucial Crypto Market Structure Bill

Urgent: Coinbase CEO Pushes for Crucial Crypto Market Structure Bill

BitcoinWorld Urgent: Coinbase CEO Pushes for Crucial Crypto Market Structure Bill The cryptocurrency world is buzzing with significant developments as Coinbase CEO Brian Armstrong recently took to Washington, D.C., advocating passionately for a clearer regulatory path. His mission? To champion the passage of a vital crypto market structure bill, specifically the Digital Asset Market Clarity (CLARITY) Act. This legislative push is not just about policy; it’s about safeguarding investor rights and fostering innovation in the digital asset space. Why a Clear Crypto Market Structure Bill is Essential Brian Armstrong’s visit underscores a growing sentiment within the crypto industry: the urgent need for regulatory clarity. Without clear guidelines, the market operates in a gray area, leaving both innovators and investors vulnerable. The proposed crypto market structure bill aims to bring much-needed definition to this dynamic sector. Armstrong explicitly stated on X that this legislation is crucial to prevent a recurrence of actions that infringe on investor rights, citing past issues with former U.S. Securities and Exchange Commission (SEC) Chair Gary Gensler. This proactive approach seeks to establish a stable and predictable environment for digital assets. Understanding the CLARITY Act: A Blueprint for Digital Assets The Digital Asset Market Clarity (CLARITY) Act is designed to establish a robust regulatory framework for the cryptocurrency industry. It seeks to delineate the responsibilities of key regulatory bodies, primarily the SEC and the Commodity Futures Trading Commission (CFTC). Here are some key provisions: Clear Jurisdiction: The bill aims to specify which digital assets fall under the purview of the SEC as securities and which are considered commodities under the CFTC. Investor Protection: By defining these roles, the act intends to provide clearer rules for market participants, thereby enhancing investor protection. Exemption Conditions: A significant aspect of the bill would exempt certain cryptocurrencies from the stringent registration requirements of the Securities Act of 1933, provided they meet specific criteria. This could reduce regulatory burdens for legitimate projects. This comprehensive approach promises to bring structure to a rapidly evolving market. The Urgency Behind the Crypto Market Structure Bill The call for a dedicated crypto market structure bill is not new, but Armstrong’s direct engagement highlights the increasing pressure for legislative action. The lack of a clear framework has led to regulatory uncertainty, stifling innovation and sometimes leading to enforcement actions that many in the industry view as arbitrary. Passing this legislation would: Foster Innovation: Provide a clear roadmap for developers and entrepreneurs, encouraging new projects and technologies. Boost Investor Confidence: Offer greater certainty and protection for individuals investing in digital assets. Prevent Future Conflicts: Reduce the likelihood of disputes between regulatory bodies and crypto firms, creating a more harmonious ecosystem. The industry believes that a well-defined regulatory landscape is essential for the long-term health and growth of the digital economy. What a Passed Crypto Market Structure Bill Could Mean for You If the CLARITY Act or a similar crypto market structure bill passes, its impact could be profound for everyone involved in the crypto space. For investors, it could mean a more secure and transparent market. For businesses, it offers a predictable environment to build and scale. Conversely, continued regulatory ambiguity could: Stifle Growth: Drive innovation overseas and deter new entrants. Increase Risks: Leave investors exposed to unregulated practices. Create Uncertainty: Lead to ongoing legal battles and market instability. The stakes are incredibly high, making the advocacy efforts of leaders like Brian Armstrong all the more critical. The push for a clear crypto market structure bill is a pivotal moment for the digital asset industry. Coinbase CEO Brian Armstrong’s efforts in Washington, D.C., reflect a widespread desire for regulatory clarity that protects investors, fosters innovation, and ensures the long-term viability of cryptocurrencies. The CLARITY Act offers a potential blueprint for this future, aiming to define jurisdictional boundaries and streamline regulatory requirements. Its passage could unlock significant growth and stability, cementing the U.S. as a leader in the global digital economy. Frequently Asked Questions (FAQs) What is the Digital Asset Market Clarity (CLARITY) Act? The CLARITY Act is a proposed crypto market structure bill aimed at establishing a clear regulatory framework for digital assets in the U.S. It seeks to define the roles of the SEC and CFTC and exempt certain cryptocurrencies from securities registration requirements under specific conditions. Why is Coinbase CEO Brian Armstrong advocating for this bill? Brian Armstrong is advocating for the CLARITY Act to bring regulatory certainty to the crypto industry, protect investor rights from unclear enforcement actions, and foster innovation within the digital asset space. He believes it’s crucial for the industry’s sustainable growth. How would this bill impact crypto investors? For crypto investors, the passage of this crypto market structure bill would mean greater clarity on which assets are regulated by whom, potentially leading to enhanced consumer protections, reduced market uncertainty, and a more stable investment environment. What are the primary roles of the SEC and CFTC concerning this bill? The bill aims to delineate the responsibilities of the SEC (Securities and Exchange Commission) and the CFTC (Commodity Futures Trading Commission) regarding digital assets. It seeks to clarify which assets fall under securities regulation and which are considered commodities, reducing jurisdictional ambiguity. What could happen if a crypto market structure bill like CLARITY Act does not pass? If a clear crypto market structure bill does not pass, the industry may continue to face regulatory uncertainty, potentially leading to stifled innovation, increased legal challenges for crypto companies, and a less secure environment for investors due to inconsistent enforcement and unclear rules. Did you find this article insightful? Share it with your network to help spread awareness about the crucial discussions shaping the future of digital assets! To learn more about the latest crypto market trends, explore our article on key developments shaping crypto regulation and institutional adoption. This post Urgent: Coinbase CEO Pushes for Crucial Crypto Market Structure Bill first appeared on BitcoinWorld.
Share
Coinstats2025/09/18 20:35