0

I'm new to ActionHero and I have a need to add something to the queue, wait until that is finished and get the data back, then proceed with another queue'd item before responding to the client. Looks like this:

  1. API client hits /foo
  2. the foo action calls the bar action and waits...
  3. When bar is finished it returns a value of 123abc
  4. 123abc is then passed to the queue again for the task that needs it

It's worth noting here, I understand this isn't optimal, but this involves 3 servers. /foo hits my Node ActionHero server, 123abc comes from a Java server (think of it as an authentication service), and then my Node ActionHero server is going to send this off to be picked up by a .NET server.

The way I have it setup now with a task does hit the Java server and the Java server logs out the value I need but in the code below it's an empty object

The run() in ACTION:

api.actions.enqueue('MyJavaServerTask', {...}, function(error, toRun){
  console.log(arguments) // <-- returns { '0': null, '1': true }
  data.response.success = true
  api.queue.push(data, next)
})

TASK:

exports.task = {
  name: 'MyJavaServerTask',
  description: 'My Java Server Task',
  frequency: 0,
  queue: 'default',
  run: function (api, params, next) {
    var job = {
      response: {},
      connection: {id: 'none'},
      authorization: params.authorization,
      params: {
        apiVersion: '1',
        action: 'MyJavaServerTask',
        ...
      }
    }
    api.queue.push(job, function() {
      console.log(arguments) // <-- returns {}
      next()
    })
  }
}

On the Java server though, again, I do see the request and it's successful and it returns the right JSON. The log for that looks like

15:19:22.542 [run-main-0] INFO  application - apiq read: {"id":"none","params":{"apiVersion":"1","action":"MyJavaServerTask"}}
generating tables and key
15:19:22.543 [run-main-0] INFO  application - result: {"key":"..."}

So... how do I get that key from there back to be used to append to the next queue'd item?

Oscar Godson
  • 31,662
  • 41
  • 121
  • 201
  • You aren't being very clear about exactly how you call the back-end server and what you expect to happen. `api.queue` isn't an ActionHero core middleware so obviously it's something you've supplied. `api.actions.enqueue` also is not a standard AH metaphor - did you mean `api.tasks`? Unless you can provide a Gist/Plunkr/etc of your ACTUAL code it's very hard for us to help you. – Chad Robinson Aug 27 '16 at 05:36
  • so, `/foo` is in an AH action normally triggered by an HTTP(S) request that must hit some sort of `bar()` and `baz()` functionality sequentially. But, `bar()` is what exactly, an endpoint that operates how and with what response characteristics? And, likewise, `baz()` (your .NET step) is also what? – alphadogg Aug 27 '16 at 20:14

1 Answers1

2

If the API client expects a synchronous response from the Java backend, why not just call the request from within the action?

exports.foo = {
  name: 'foo',
  description: 'foo',
  outputExample: {},
  inputs: {}

  run: function(api, data, next){
    var request = require('request);
    request.get('bar.com/bar', function(error, response){
       if(error){ return next(error); }
       var body = JSON.stringify(response.body);
       data.response = body;
       return next();
    });
  }

};

In node, this pattern is great, because while your action is waiting, the node server can serve other requests.

I can't quite tell if your task example is enqueuing another task? What is api.queue? Either way, there is no way to get a value from a task back to an action. If you want the client to POLL, you can have your task store the eventual response from the Java server in redis or somewhere else, and then create another action which checks if the key exists, and returns it if it does.

Evan
  • 3,191
  • 4
  • 29
  • 25
  • The Java server isn't a RESTful server so I can't call it directly. It pulls actions off Redis which are being queued up. I _could_ have it call itself like /foo/bar but that seemed a bit janky. – Oscar Godson Aug 26 '16 at 22:51
  • This is how I would do it, although I'd probably refactor the request code into an initializer - you can see where as you start using this pattern you're going to need to hit that backend server with more requests. Then the action can just be `request1` -> `request2` -> `response`. – Chad Robinson Aug 26 '16 at 22:51