puniverse / pulsar

Fibers, Channels and Actors for Clojure
http://docs.paralleluniverse.co/pulsar/
Other
910 stars 53 forks source link

call! in gen-event handler #55

Closed colinyip closed 8 years ago

colinyip commented 8 years ago

Not sure this is an issue or i am just using it in a wrong way, would be great to clarify this :)

Whenever i execute call! inside a handler of gen-event (EventSourceActor), it throws a NullPointerException at co.paralleluniverse.strands.Strand park

for example:


(def event-handler1 (spawn (gen-event (fn []
                                          (println "event handler 1 started"))
                                        (fn [cause]
                                          (println "event handelr 1 exited" {:cause cause})))))

(def server1 (spawn (gen-server (reify Server
                                    (init [_]
                                      (println "server1 started"))
                                    (handle-call [_ _ _ message]
                                      (do
                                        (println "server1 get message from handle call" {:message message})
                                        message))
                                    (handle-cast [_ _ _ message]
                                      (println "server1 get message from handle cast" {:message message}))))))

(def handler1 (fn [& args]
                  (println "handling event with handler1")
                  (call! server1 [:add 1])
                  (println "finished handling event with handler1")))

(add-handler! event-handler1 handler1)

(notify! event-handler1 [:go {}])

Exceptions:

Exception in Fiber "fiber-10000364" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.NullPointerException
    at co.paralleluniverse.strands.Strand.park(Strand.java:493)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(ConditionSynchronizer.java:54)
    at co.paralleluniverse.actors.Mailbox.await(Mailbox.java:90)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(SelectiveReceiveHelper.java:145)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(RequestReplyHelper.java:174)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:102)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:80)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(actors.clj:669)
    at flow_manager.event_handler_test$handler1.doInvoke(form-init8243819381685639938.clj:3)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(actors.clj:720)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers(EventSourceActor.java:245)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage(EventSourceActor.java:225)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior(BehaviorActor.java:237)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:293)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:36)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1026)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.strands.Strand.park(java.lang.Object) (Strand.java:493 bci: 57)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(int) (ConditionSynchronizer.java:54 bci: 255)
    at co.paralleluniverse.actors.Mailbox.await(int) (Mailbox.java:90 bci: 99)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(long,java.util.concurrent.TimeUnit,co.paralleluniverse.actors.MessageProcessor) (SelectiveReceiveHelper.java:145 bci: 917)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(co.paralleluniverse.actors.ActorRef,co.paralleluniverse.actors.behaviors.RequestMessage,long,java.util.concurrent.TimeUnit) (RequestReplyHelper.java:174 bci: 663)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object,long,java.util.concurrent.TimeUnit) (Server.java:102 bci: 192)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object) (Server.java:80 bci: 274)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(java.lang.Object,java.lang.Object) (actors.clj:669 bci: 133)
    at flow_manager.event_handler_test$handler1.doInvoke(java.lang.Object) (form-init8243819381685639938.clj:3 bci: 200)
    at clojure.lang.RestFn.invoke (RestFn.java:408 bci: 50)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:36 bci: 5)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(java.lang.Object) (actors.clj:720 bci: 8) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers (EventSourceActor.java:245 bci: 81) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage (EventSourceActor.java:225 bci: 645) !! (instrumented suspendable calls at: [])
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior (BehaviorActor.java:237 bci: 137)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:293 bci: 122)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:36 bci: 1) (optimized)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691 bci: 222)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51 bci: 148)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1026 bci: 11)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1021 bci: 1)
Exception in Fiber "fiber-10000364" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.NullPointerException
    at co.paralleluniverse.strands.Strand.park(Strand.java:493)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(ConditionSynchronizer.java:54)
    at co.paralleluniverse.actors.Mailbox.await(Mailbox.java:90)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(SelectiveReceiveHelper.java:145)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(RequestReplyHelper.java:174)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:102)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:80)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(actors.clj:669)
    at flow_manager.event_handler_test$handler1.doInvoke(form-init8243819381685639938.clj:3)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(actors.clj:720)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers(EventSourceActor.java:245)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage(EventSourceActor.java:225)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior(BehaviorActor.java:237)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:293)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:36)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1026)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.strands.Strand.park(java.lang.Object) (Strand.java:493 bci: 57)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(int) (ConditionSynchronizer.java:54 bci: 255)
    at co.paralleluniverse.actors.Mailbox.await(int) (Mailbox.java:90 bci: 99)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(long,java.util.concurrent.TimeUnit,co.paralleluniverse.actors.MessageProcessor) (SelectiveReceiveHelper.java:145 bci: 917)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(co.paralleluniverse.actors.ActorRef,co.paralleluniverse.actors.behaviors.RequestMessage,long,java.util.concurrent.TimeUnit) (RequestReplyHelper.java:174 bci: 663)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object,long,java.util.concurrent.TimeUnit) (Server.java:102 bci: 192)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object) (Server.java:80 bci: 274)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(java.lang.Object,java.lang.Object) (actors.clj:669 bci: 133)
    at flow_manager.event_handler_test$handler1.doInvoke(java.lang.Object) (form-init8243819381685639938.clj:3 bci: 200)
    at clojure.lang.RestFn.invoke (RestFn.java:408 bci: 50)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:36 bci: 5)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(java.lang.Object) (actors.clj:720 bci: 8) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers (EventSourceActor.java:245 bci: 81) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage (EventSourceActor.java:225 bci: 645) !! (instrumented suspendable calls at: [])
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior (BehaviorActor.java:237 bci: 137)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:293 bci: 122)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:36 bci: 1) (optimized)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691 bci: 222)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51 bci: 148)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1026 bci: 11)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1021 bci: 1)

the way i dealt with it at the moment is wrapping the whole handler logic in a fiber and it works pretty well :)

Thanks!

circlespainter commented 8 years ago

What is your use case, or more precisely: why do you need to call strand-blocking blocking operations like call from event handlers?

circlespainter commented 8 years ago

@colinyip Asking because at present handlers are not suspendable in order to keep the events actor "reactive" (disallow handlers to block each other) but Quasar docs seem to suggest otherwise, so there's definitely something to do for us: either remove this restriction or change the docs.

Your use case can help us decide which route to take. Thanks!

colinyip commented 8 years ago

@circlespainter thanks for the reply! In my case, the handler i created need to process some task that relies on the state of another actor, so it need to make a strand-blocking call to fetch the data before it could finish executing. I realised later on that wrapping the whole handler logic in a fiber actually works a bit better because it allows multiple event handling happen in parallel, which suits better in for the feature i am working.

So this is not something must have for me. But in my opinion, I would vote for having the restriction removed. It's more consistent with the Quasar docs (according to your comments) and It should be up to the user how they want it to work :) Or perhaps update the doc so that people are aware of this behavior?

Thanks!

circlespainter commented 8 years ago

It is now discouraged but supported. Thanks for your feedback!

colinyip commented 8 years ago

thanks 👍