Skip to content

Async

Async example demonstrating how to use correlation IDs

The example represents an async request that checks if a file exists and creates that file if it does not. No real files are used; instead a boolean is used.

Startup a q server on port 8081 for demonstration.

\l kurl.q
port:"8081"
server:hsym `$":localhost:",port
system "q -p ",port

We are going to define the server’s API to check a boolean and return either "hello world", or a 404 saying no file exists.

We define the function locally below, and install it dynamically over IPC

remotezph:{
  $[fileexists; .h.hy[`txt] "hello world"; .h.hn["404";`txt; "No file found"]] }

server (set;`fileexists;0b)
server (set;`.z.ph; remotezph)

server (set;
  `.z.pp; 
  {fileexists::1b; .h.hy[`json] .j.j `time`file!(.z.p; `:filename.txt)} )

// Have the server quit after 5 minutes of up time, 
// so you don't run this code and leave it up forever
server (set;`.z.ts; {[start;x] if[x > start + 00:05:00; exit 0]; }[.z.p;])
server (system;"t 1000")

Now we define the client API that uses Kurl to make async requests.

// Simple async handler that creates files if they don't exist
// @param id CorrelationID
// @param name Arbitrary data (in our case filename)
// @param resp (http code;response text)
onmessage:{[id; name; resp]
  event: cid ? id;
  if[event ~ `getfile;    checkGETResult[name; resp]];
  if[event ~ `createfile; getfile name]; }

// Correlation ID - Project in an ID that makes responses meaningful to you
// In a more complex app you may save a dynamic dictionary of these
// The GUIDs here are meaningless, but demonstrate IDs can be a complex shape
ids:2?0ng;
cid: (!) . flip (
  (`getfile;    ids 0);
  (`createfile; ids 1) )

// Async POST file creation
createfile:{[name]
  body:.j.j `name`content!(name;"hello world");
  opts:`body`callback!(body;onmessage[cid `createfile; name;]);
  .kurl.async ("http://localhost:8081/v1/createfile"; `POST; opts) }

// Async GET file
getfile:{[name]
  loginfo "asking for a file";
  opts:``callback!(::;onmessage[cid `getfile; name;]);
  .kurl.async ("http://localhost:8081/v1/getfile?file=myFile"; `GET; opts) }

// Return response if file exists, else create it
checkGETResult:{[name; resp]
  $[404 = resp 0;
      [ loginfo "file not found, making it"; createfile name];
    200 = resp 0;
      [ loginfo "file now found"; resp 1];
    [ loginfo "got some unexpected error"]] }

loginfo:{show enlist (.z.p; x);}

To kick off the demo, make a request to ask for myFile! Wait for the server on port 8081 to come up before running

getfile `myFile.txt;