JDP Science Tools

cancel
Showing results for 
Search instead for 
Did you mean: 

Using Notifiers with a Future Token for Replies

I know this is breaking the paradigm, and I'll likely change the approach, but it should still work yet I get errors when I try it, so I'd like to get to the bottom of it if possible to enhance my understanding.

 

I have a main actor that launches two child actors, "A" and "B". A and B are decoupled. One of A's states requires some information from B (it doesn't know it comes from B, it just asks for this info and main handles the redirection). Typically when passing info up the tree one uses Notifiers (Event), and that's not used for requests, but in this instance I thought I'd try it.

 

So A sends a Notify Event message that contains a Future Token in readiness for the recipient's reply. Main forwards the notifier message onto B for handling, which duly replies with a message to the Token. However, this always fails, with one of two errors, either code 1 "Future Token Invalid", or code 42 "Future already filled".

 

Checking the Observer Registry shows I have one registered observer of A, which is Main. SO I don't have multiple observers receiving the message, which might have explained the second error.

 

If I check the validity of the Future Token in B before sending, I see it's not valid, which means it's already destroyed before I get a chance to reply. The whole process takes milliseconds, so it's not timing out. By using stepping I can ensure A isn't trying to read the token before B has populated it, but it's still invalid. It's like the token never got to B in the first place. I've scoured the Messenger library code and I don't see how the reply token could be being stripped from the message. 

 

Looking for help on diagnosing this.

 

 

Thoric (CLA, CLED, CTD and LabVIEW Champion)


0 Kudos
Message 1 of 6
(3,198 Views)

Additional. If I place a breakpoint on "Redeem Future Token" in A so that it cannot read the token before B has populated it, then the Future Valid? check in B returns a True instead of a False, but an attempt to populate it returns code 42 "Future Already Filled".

 

When Redeem Future Token then executes it returns, without error, an empty message with an empty variant payload (whereas B creates a labelled message with a byte array payload).

 

Since Futures are simply a 1 element queue, I tried changing it to a 2 element queue, and in the Redeem I get the queue stats. Guess what - no more errors in B, and in A I see two messages in the queue. The second message is actually the reply from B. So where does the first message come from?

Thoric (CLA, CLED, CTD and LabVIEW Champion)


0 Kudos
Message 2 of 6
(3,189 Views)

I tried replacing this notifier with future token with a simple Query&Read instead. This takes the caller's messenger ref and sends a direct message and waits on a reply to a private message queue created on the fly. This is a slightly better approach, but interestingly I get the same issue.

 

In Actor B the Send function fails with code 1 "Input parameter is invalid" - which I assume is the internal message queue being invalid, suggesting the message reply has already been sent elsewhere and the Query&Read function has thus destroyed the queue ref. As before, the returned message is blank, no label or payload.

 

I guess somewhere in my hierarchy I have messed up and I'm responding to this incoming request with a blank (default) MSG before passing it onto Actor B? If so, I cannot see it.

Thoric (CLA, CLED, CTD and LabVIEW Champion)


0 Kudos
Message 3 of 6
(3,163 Views)

OK, so I got to the bottom of this. My situation was caused by a helper loop in Actor B. The incoming message from A (that contains the reply address) was being packaged up into a job for the helper loop to execute. However, what does the state machine do as the final case in the Messenger actor? Exactly, in the last case it sends a reply to the incoming message - a blank reply (by default). 

 

Because I was asynchronously transitioning my workload outside of the state machine, into a helper loop (that's tied the EtherCAT Scan Engine), and returning the response from there, I was inadvertently also letting the main actor state machine send it's own reply, which it always did first, rendering the reply pipeline dead to the actual reply I was trying to send.

Thoric (CLA, CLED, CTD and LabVIEW Champion)


0 Kudos
Message 4 of 6
(3,159 Views)

Ah, so your mistake was branching the message.  You forwarded one copy to a helper loop, and kept the other copy in the main loop. Thus you had two receivers that called Reply on the message, giving two replies.  

 

If forwarding a message to be handled by someone else, it is important not to reply to the message yourself.

0 Kudos
Message 5 of 6
(3,147 Views)

General rule for replies:

  • Always call Reply in handling a message, even if the is no useful info to reply with.  The sender may have its own reasons for wanting an acknowledgment.
  • Call Reply only once.
  • Call Reply as the last action in handling a message; the reply can be used by the caller to know when the action it requested is completed.
0 Kudos
Message 6 of 6
(3,145 Views)