cancel
Showing results for 
Search instead for 
Did you mean: 

Converting callbacks to synchronous calls

Victor_Wong
New Contributor
Hi,

I am working with an API that is callback based (think alternating sets of request and requestCompleted messages) and in an attempt to avoid writing an ugly and difficult-to-maintain chain of nested callbacks, I am looking for a way to convert those calls into a function that only returns when the reply is received.  I thought of two ways of doing this, but both seem like a bit of a hack to me and I was wondering if there was a more cleaner/native way.

The first was to use q's C interface to add a layer between my app and the API endpoint (both q processes), taking a synchronous request, sending it on as an asynchronous call, and replying to the client only when it received the asynchronous reply.  (You would open two sockets, listening to one and then sending on the other, alternately.)  The second was to use Andrey Kozyrev's debugger to run my app, adding in breakpoints where I needed to wait for asynchronous replies, and continuing execution when I received a callback.  (The new debugger doesn't seem to be able to pause and resume execution.)

Neither of those seem efficient, so I was wondering if there was a more native way to either 1) respond to a synchronous call asynchronously, or 2) pause execution of the script while responding to network events, and resuming when a callback was received.

Thanks for your help,
Victor
4 REPLIES 4

jwbuitenhuis
New Contributor
Is this a inter-process situation or a HTTP web application? Assuming the latter, you could use a web socket and give out a unique id to the caller for each request, and then send the response when it is ready using that id.

The initial request returns immediately.

mkeenan1
New Contributor
Please provide a message example and required functionality for this message if possible. 

Sent from my iPhone

Here's a snippet of the nested callbacks I am referring to:

coords:(101 205;120 673;...); i:0; sensors:(); readings:();
{(neg h) `searchSensors x} each coords;
sensorResults:{i+:1; 
  $[i < count coords;
     sensors,:x;
     [i::0; sensorResults::{i+:1; $[i < count sensors; readings,:x; [...]]}; 
       {(neg h) `querySensor x} each sensor]]};

Here's what I would ideally like to work with:

{h (`querySensor;x)} each raze {h (`searchSensors;x)} each coords;

Thanks again for your help.

thanks to charles for this one...

so at the bottom level, you have "my app and the API endpoint (both q processes)"
and you want a "function that only returns when the reply is received" (turn an async call into a sync call)
this is possible when you have two q processes:

in your 'sensors' session:
$ q -p 5001
\l sensor.q 
...

in the client:
$ q
q)h:hopen 5001
q)f:{neg[h]({neg[.z.w]value x};x);h[]}
q)f(til;4)
0 1 2 3

note that f sends an async request, but waits on the next message with h[]
.z.ps in the server should retain its default semantics (returning value x)
note that the function {neg[.z.w]value x} is evaluated on 5001, so .z.w is the handle of the client process
note that if 5001 handles other requests, h[] may return the wrong message
nesting sync calls is not recommended and it's likely that f suffers the same limitation

so f can be used to achieve the result you want:
 {f (`querySensor;x)} each raze {f (`searchSensors;x)} each coords;

and you can reduce the amount of traffic with something like:
 f(each;`querySensor;raze f(each;`searchSensors;coords))

On 10 July 2017 at 08:34, Victor Wong <victor.wong@gmail.com> wrote:
Here's a snippet of the nested callbacks I am referring to:

coords:(101 205;120 673;...); i:0; sensors:(); readings:();
{(neg h) `searchSensors x} each coords;
sensorResults:{i+:1; 
  $[i < count coords;
     sensors,:x;
     [i::0; sensorResults::{i+:1; $[i < count sensors; readings,:x; [...]]}; 
       {(neg h) `querySensor x} each sensor]]};

Here's what I would ideally like to work with:

{h (`querySensor;x)} each raze {h (`searchSensors;x)} each coords;

Thanks again for your help.