Actors and Overflow Block Policy

56 views
Skip to first unread message

James Bridges

unread,
Sep 18, 2015, 6:33:08 PM9/18/15
to quasar-pulsar-user
Hello, I would like some clarity on the description of the overflow policies in reference to the send/SendPort side of things. I was monkeying around with the Block policy and am noticing some weird behavior. As per the documentation: "Sends a message to the actor, possibly blocking until there's room available in the mailbox. If the mailbox is full, this method may block or silently drop the message. The behavior is determined by the mailbox's co.paralleluniverse.strands.channels.Channels.OverflowPolicy, set at construction time. However, unlike regular channels, this method never throws co.paralleluniverse.strands.queues.QueueCapacityExceededException. If the mailbox overflows, and has been configured with the co.paralleluniverse.strands.channels.Channels.OverflowPolicy.THROW policy, the exception will be thrown into the actor." 

The following code forces a production of: 
Exception in Fiber "fiber-10000002" co.paralleluniverse.strands.queues.QueueCapacityExceededException
at co.paralleluniverse.strands.channels.QueueChannel.sendNonSuspendable(QueueChannel.java:300)
at co.paralleluniverse.actors.Actor.internalSendNonSuspendable(Actor.java:418)
at co.paralleluniverse.actors.Actor.internalSend(Actor.java:409)
at co.paralleluniverse.actors.ActorRef.send(ActorRef.java:75)
at com.mycompany.actortest.Actors$1.doRun(Actors.java:44)
at com.mycompany.actortest.Actors$1.doRun(Actors.java:28)
at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
at co.paralleluniverse.actors.Actor.run(Actor.java:259)
at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1024)


with the BLOCK overflow policy specified. Small test case is attached. Am I doing something inherently wrong?

import co.paralleluniverse.actors.Actor;
import co.paralleluniverse.actors.ActorRef;
import co.paralleluniverse.actors.BasicActor;
import co.paralleluniverse.actors.MailboxConfig;
import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.FiberForkJoinScheduler;
import co.paralleluniverse.fibers.FiberScheduler;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.channels.Channels;

public class ActorTest {

    public static void main(String[] args) throws Exception {

        final ActorRef a = spawnActor(new BasicActor<Message, Void>(new MailboxConfig(10, Channels.OverflowPolicy.BLOCK)) {
            @Override
            protected Void doRun() throws InterruptedException, SuspendExecution {
                while (true) {
                    Message m = receive();
                    long recv = System.nanoTime();
                    System.out.println(m.num + " current: " + recv + " Sent: " + m.content + "diff: " + (recv - m.content));
                }
            }
        }).ref();

        spawnActor(new BasicActor<Integer, Void>(new MailboxConfig(10, Channels.OverflowPolicy.BLOCK)) {
            @Override
            protected Void doRun() throws InterruptedException, SuspendExecution {
                for (int i = 0; i < 100; i++) {
                    a.send(new Message(i, System.nanoTime()));
                }
                return null;
            }
        });
        
        Thread.sleep(1000000);
    }

    private static <Message, V> Actor<Message, V> spawnActor(Actor<Message, V> actor) {
        new Fiber(actor).start();
        return actor;
    }

    static class Message {

        public final int num;
        public final long content;

        public Message(int num, long content) {
            this.num = num;
            this.content = content;
        }
    }
}

fa...@paralleluniverse.co

unread,
Sep 20, 2015, 10:38:59 AM9/20/15
to quasar-pulsar-user
Hi, I suggest that you start the actor with its "spawn" method. You can also use "ActorRef<Message>" instead of the raw "ActorRef" and rather than sleeping in the main thread you could use "Actor.get" or "join" f.e. on the sending actor.

The exception you get is due to an (intentional) limitation of actor mailboxes which cannot block (cfr. Erlang which disallows limiting mailbox sizes). The reason is that blocking mailboxes makes some other present/future features much more difficult to implement.

It is of course not intentional for it to be undocumented/unchecked, so could you open an issue about that? So that the authorship of this finding will be yours and we'll fix the docs + add a fail-fast check upon "MailboxConfig" construction (or around there) in relation to it.

For message exchanges between (co-located) actors where you absolutely need blocking semantics you could just use plain channels.

Thanks,
-- Fabio
Reply all
Reply to author
Forward
0 new messages