Skip to content
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

Analyzer Rule: don't allow users to stash the same message twice #104

Open
Aaronontheweb opened this issue Nov 4, 2024 · 0 comments
Open
Labels
AK2000 API usage rules

Comments

@Aaronontheweb
Copy link
Member

We should ensure that a user can't write code like this:

using System;
using Akka.Actor;
using Akka.Event;
using Akka.Actor.Stash;

public class StashExampleActor : ReceiveActor, IWithStash
{
    public IStash Stash { get; set; }

    private readonly ILoggingAdapter _log = Context.GetLogger();

    public StashExampleActor()
    {
        // Initial state is WaitingForData
        WaitingForData();
    }

    private void WaitingForData()
    {
        Receive<string>(msg =>
        {
            _log.Info($"Received message: {msg}. Transitioning to Processing state and stashing.");
            
            // Stash the message twice
            Stash.Stash();
            Stash.Stash(); // illegal - means we're going to create a duplicate message
            
            Become(Processing);
            Self.Tell("ContinueProcessing"); // Move to next state to process the stashed messages
        });
    }

    private void Processing()
    {
        Receive<string>(msg =>
        {
            _log.Info($"Received message: {msg} while in Processing state.");
            UnstashAll();
            Become(WaitingForData);
        });
    }

However, the analyzer also needs to be sophisticated enough to know that this code is not that:

using System;
using Akka.Actor;
using Akka.Event;
using Akka.Actor.Stash;

public class ConditionalStashExampleActor : ReceiveActor, IWithStash
{
    public IStash Stash { get; set; }

    private readonly ILoggingAdapter _log = Context.GetLogger();

    public ConditionalStashExampleActor()
    {
        // Initial state is WaitingForData
        WaitingForData();
    }

    private void WaitingForData()
    {
        Receive<string>(msg =>
        {
            _log.Info($"Received message: {msg}");

            // Conditional branching for stashing based on message content
            if (msg == "StashCondition1")
            {
                _log.Info("Condition 1 met, stashing message.");
                Stash.Stash();
            }
            else if (msg == "StashCondition2")
            {
                _log.Info("Condition 2 met, stashing message.");
                Stash.Stash();
            }
            else
            {
                _log.Info("No stashing condition met, processing message immediately.");
                // Perform processing directly, no stashing
            }

            // Transition to Processing state after conditionally stashing
            Become(Processing);
            Self.Tell("ContinueProcessing"); // Move to next state to process any stashed messages
        });
    }

    private void Processing()
    {
        Receive<string>(msg =>
        {
            _log.Info($"Processing state received message: {msg}");
            UnstashAll();
            Become(WaitingForData);
        });
    }

    protected override void PreStart()
    {
        _log.Info("ConditionalStashExampleActor started.");
    }

    protected override void PostStop()
    {
        _log.Info("ConditionalStashExampleActor stopped.");
    }
}

There are multiple Stash.Stash() calls occurring inside the same Receive<T>, but they are cleanly separated via conditional branches - and therefore should not trigger this rule.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AK2000 API usage rules
Projects
None yet
Development

No branches or pull requests

1 participant