oboe.js icon indicating copy to clipboard operation
oboe.js copied to clipboard

Async Transforms

Open TSteele27 opened this issue 9 years ago โ€ข 19 comments

In the documents it mentions that you can transform the json streaming through in by returning a value from the callback. It would be nice if this operation could work async as well. We have a pattern in our micro systems where links are returned as a result and before passing this back to the user I like to follow the links server side so the user gets a set of hydrated results. Currently I have a rather ugly solution to this, but an async transform function would make this really simple.

TSteele27 avatar Dec 21 '15 19:12 TSteele27

@TSteele27 What's your current solution like? I know the current code waits for a listener to finish before the next gets started, so maybe what it could do is add a callback option to let that back-pressure mechanism know that it's getting an async transform.

JuanCaicedo avatar Dec 21 '15 19:12 JuanCaicedo

Adding a cb to the transform would work. :)

TSteele27 avatar Dec 22 '15 12:12 TSteele27

Async transforms would also help for my use-case as well.

scotthovestadt avatar Feb 10 '16 05:02 scotthovestadt

I'm going to pick this issue as the one to put my thoughts into, though there are a couple related issues I've mentioned.

I think the code that would need to change is here, and there the related test are here.

The api I'm thinking about would be something like (note that arg2 and arg3 are already taken, but I'm not sure by what since couldn't find that in the API.

.node('pattern', function( matched, arg2, arg3, cb ) {
    return asyncTransform( function(err, data){
      cb(null, data);
    }, 0);
  }
})

But I'm having trouble figuring out how to fit that into the existing code. The existing code relies on having a return value, which I think would be undefined in the case of async transforms.

JuanCaicedo avatar Feb 14 '16 16:02 JuanCaicedo

What if you returned an async function, promise or stream from the pattern listener? This would maintain the current pattern of returning something from the listener to indicate a transform and we would just have to add some code around handling the different async options.

TSteele27 avatar Feb 14 '16 18:02 TSteele27

Great ideas @TSteele27! That first one seems really promising to me. You could return a function that would be called by the library code, as opposed to actually invoking that function.

I really like the idea of using promises, although since Oboe is all ES5 and tries not to introduce dependencies, I'm not entirely sure if we could do that right now :confused:

Not entirely sure about how to do this with a stream, what would you have in mind?

JuanCaicedo avatar Feb 14 '16 21:02 JuanCaicedo

Returning an async function is IMO the easiest of the 3 to implement. As for returning a promise I'm not convinced we would have to add a (production) dependency on a promise library since we would be using a promise returned by the client code, not generating a promise. As long as the promise library followed the promise spec would could rely on that without introducing a dependency. We may have to add a devDependency on a promise library to test to make sure that the code works, but I don't see a reason we would need to add a production dependency. Granted type checking a promise might be a bit difficult, but if we look for a .then method on the listener return value that would be a pretty good indication its a promise.

As for handling a stream, this one would be the most difficult, not quite sure how I would go about doing it since I am not intimately familiar with the oboe source code. The simplest thing to do would be to callbackify it in the library code and just handle it like async function, but if we wanted to support the actual streaming it would probably get more complex.

TSteele27 avatar Feb 15 '16 14:02 TSteele27

I agree strongly that promises should be an option if possible, even at the cost of introducing a dependency.

This 8k library provides "native promises only" as a polyfill. It's very bare-bones: https://github.com/getify/native-promise-only

scotthovestadt avatar Feb 15 '16 18:02 scotthovestadt

I also need flow control in oboe as I'm reading a big json file form disk to stream it to the network.

@JuanCaicedo I think what you named arg2 and arg3 are documented here: http://oboejs.com/api#node-event, those are the path and ancestors of the matched parameter (named node in the doc).

fredfp avatar Feb 20 '16 12:02 fredfp

Nice @fredfp, thanks!

JuanCaicedo avatar Feb 21 '16 17:02 JuanCaicedo

Hey folks. Has there been any movement or solution found to this issue? I'm currently stuck on the same thing...

lincolnthree avatar Feb 02 '18 00:02 lincolnthree

@lincolnthree nope, unfortunately I wouldn't count on their being any ๐Ÿ˜•There's not much work being done here

JuanCaicedo avatar Feb 09 '18 01:02 JuanCaicedo

@JuanCaicedo Thanks. I ended up removing Oboe and chunking the file on the server side to get around this limitation. Can't actually stream properly if you're still loading the entire stream into memory. If there's no way to block the back-pressure then there's no point :/ Otherwise this library is great!

lincolnthree avatar Feb 09 '18 15:02 lincolnthree

I'm interested in implementing this! @JuanCaicedo (or any other collaborators), do you have any pointers or thoughts about how to do it best?

wilg avatar Jun 23 '18 00:06 wilg

Hi @wilg awesome, I'm excited that you're excited! I don't know exactly where to start, but @Aigeec might have more thought since he's looked at more of the files recently? If not, I can take a look and send you some thoughts ๐Ÿ˜€If you haven't gotten some feedback on this by Friday, feel free to ping me (I'm pretty forgetful ๐Ÿ™ˆ๐Ÿ˜…)

JuanCaicedo avatar Jun 25 '18 17:06 JuanCaicedo

Cool, trying to get my dev environment setup but am running into issues which I've documented in https://github.com/jimhigson/oboe.js/issues/174. Any help is appreciated. I'll keep digging around.

wilg avatar Jun 25 '18 23:06 wilg

Instead of depending on promises, or hoping the user will return a promise-compatible object and trying to detect that, why not have another special helper value/method like oboe.drop?

oboe('/myapp/people')
   .node('people.*', function(person) {
      return oboe.await(function(resolve) {
         setTimeout(resolve, 100);
      });
   });

crabmusket avatar Aug 15 '19 01:08 crabmusket

Hi guys, any news on this? I too think oboe.await should be a great way of adding async callbacks without introducing dependencies on promises. In my case it would be useful to send data while streaming:

oboe('/myapp/people')
   .node('people.*', function(person) {
       return oboe.await(function(resolve) {
               stream.write(person,(err) => resolve(oboe.drop));
       });
   });

dam0vm3nt avatar Oct 07 '20 07:10 dam0vm3nt

Just adding my need for this as well. Something like oboe.await would be amazing. I'm streaming JSON results from a server (ultimately from Elasticsearch using ES's scroll method), and need a way to process nodes on the client asynchronously as they are received.

itjustwerks avatar May 25 '21 14:05 itjustwerks