Skip to content

Reconsider agent use #420

Description

@ploeh

While being aware of ADR-0008: Agent Architecture I'm quite concerned about this architecture.

As far as I can tell from makeAppEnv, most of the system runs through five agents:

        let formularyAgent = createFormularyAgent provider
        let orderCtxAgent = createOrderCtxAgent logAgent logger provider
        // [...]
        let orderPlanAgent = createOrderPlanAgent logAgent provider orderCtxPort
        let nutritionAgent = createNutritionAgent logger provider orderCtxPort
        let interactionAgent = createInteractionAgent ()

This seems to include read operations.

Since the entire purpose of an agent (MailboxProcessor) is to serialise operations, this entails that most operations, including read operations, are serialised.

Each agent serialises all operations on a single thread. With five agents, this seems to effectively limit the system to five threads. For particular subdomains (e.g. nutrition), a single agent means effectively single-threaded access to every operation offered by that agent.

This could become a bottleneck if the system needs to scale.

While not a trivial change, I recommend reverting ADR-0008: Agent Architecture.

If a lock-free architecture is desired, a better alternative is CQRS with a persistent queue for Commands. This may, however, be overkill for this system. For instance, ADR-0008: Agent Architecture states that a benefit of using agents is that

"The agent serialises all access to the provider, removing the need for the explicit lock inside CachedResourceProvider."

While true, other solutions exist, including using lock, introducing a custom compare-and-swap atomic cell type, leveraging thread-safe BCL types, etc.

In fact, we should seriously consider not using F# agents at all. F# agents are useful for serialising and streaming information when persistence is not a concern, which could include logging. Still in light of #416, even this may not be something that warrants agent use.

To expand, a problem with F# agents is that while they serialise operations, they offer no persistence guarantees. You could send a command to an agent, only for the server to shut down before the agent completes the operation. This is particularly a risk in cloud environments.

Metadata

Metadata

Assignees

Labels

needs investigationRequires further analysis before work can begin

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions