Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maximum call stack size exceeded on waitAll(long_list_of_simple_tasks). #227

Open
damianrr opened this issue Jun 23, 2020 · 3 comments
Open

Comments

@damianrr
Copy link

I've a long list of simple tasks (30k of them) and I'd like to be able to wait for all of them and it fails with a Maximum call stack size exceeded error

Steps to reproduce

If you run this program:

const { range, map } = require("ramda");
const { task, of, waitAll } = require("folktale/concurrency/task");                                                                                                                
const tasks = waitAll(map(of, range(1, 30000)));
tasks.run().listen({ onRejected: console.error, onResolved: console.log });

Expected behaviour

It should return a list of consecutive numbers from 1 to 29999

Observed behaviour

Yet, I get this error:

.../src/node_modules/folktale/adt/union/union.js:86 
    function makeInstance() {
                         ^                                                                                      

RangeError: Maximum call stack size exceeded
    at makeInstance (.../src/node_modules/folktale/adt/union/union.js:86:26)
    at new Deferred (.../src/node_modules/folktale/concurrency/future/_deferred.js:84:26) 
    at Task.run (.../src/node_modules/folktale/concurrency/task/_task.js:404:22)
    at Task._computation (.../src/node_modules/folktale/concurrency/task/_task.js:341:36)
    at Task.run (.../src/node_modules/folktale/concurrency/task/_task.js:445:28)
    at Task._computation (.../src/node_modules/folktale/concurrency/task/_task.js:93:32)
    at Task.run (.../src/node_modules/folktale/concurrency/task/_task.js:445:28)
    at Task._computation (.../src/node_modules/folktale/concurrency/task/_task.js:341:36)
    at Task.run (.../src/node_modules/folktale/concurrency/task/_task.js:445:28)
    at Task._computation (.../src/node_modules/folktale/concurrency/task/_task.js:93:32)

Environment

(Describe the environment where the problem happens. This usually includes:

  • OS: Arch Linux
  • JavaScript: Node v13.13.0
  • Folktale version: 2.3.2
    )
@damianrr
Copy link
Author

Any workaround/idea that could help me circumvent this issue will also be appreciated!

Thanks!

@robotlolita
Copy link
Member

This happens because all of your tasks are synchronous, and JS VMs don't deal well with recursion. waitAll ends up building a stack of tasks, and when they're evaluated synchronous it ends up filling up the bounded stack (having VMs implement tail recursion would really help here).

The work-around involves pretty much managing the stack so it doesn't fill up. So, for example, you can make all of the tasks asynchronous, in which case all of them will start on an empty stack when they run:

const { range, map } = require("ramda");
const { task, of, waitAll } = require("folktale/concurrency/task");
const asyncOf  = (x) => task(resolver => setImmediate(() => resolver.resolve(x)));
const tasks = waitAll(map(asyncOf, range(1, 30000)));
tasks.run().listen({ onRejected: console.error, onResolved: console.log });

But this has performance implications, and it's not always as straight-forward to do. In the general usage, Tasks mostly contain asynchronous computations, where this isn't as much of a problem, but these edge-cases can be pretty frustrating. Ideally Folktale would solve this (e.g.: running tasks in a stack-safe manner, at the expense of some performance), but I haven't had the time to work on it lately, so I'm not sure when/if this will be fixed.

@damianrr
Copy link
Author

Hey @robotlolita thanks for getting back to me and taking the time to give a very useful response. I don't mind them being async, what I actually need to do is a "fire and forget" type of thing, my only problem is that I tried running your snippet and it gave me the exact same error. Could you take a look at it again?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants