[REQUEST] Detect and report infinite loops / recursive or self-referential data loading
- Dominant language
- JavaScript
- Stars
- 13.4k
- Forks
- 518
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 2
Description
If you accidentally create a self-referential `DataLoader` load, the loader silently creates a loop of promises which never resolve. This is obviously a programmer error, but it can be pretty hard to diagnose when things just silently don't work, if the recursive load isn't obvious across a complex codepath.
This code demonstrates the issue:
```
import DataLoader from 'dataloader';
const dumbDataLoader = new DataLoader(
async nums => await Promise.all(nums.map(async n => await dumbDataLoader.load(n)))
);
console.log(await dumbDataLoader.load(3))
```
I'd expect to get some sort of warning or error from DataLoader to try to pin down the issue, but instead I only get this warning from Node (which in practise won't pop up for a more complex server):
```
Warning: Detected unsettled top-level await at index.js:7
console.log(await doubleDataLoader.load(3))
```
---
Worse, a variation of this can pop up even when the loads are technically not infinitely recursive, since you can have one batch waiting on a result from the same batch. Consider this code:
```
import DataLoader from 'dataloader';
const factDataLoader = new DataLoader(
async nums => await Promise.all(nums.map(async n => {
if (n == 0) return 1;
return n * (await factDataLoader.load(n - 1));
}))
);
// This works:
console.log(await factDataLoader.load(0));
console.log(await factDataLoader.load(1));
factDataLoader.clearAll();
// This does not:
console.log(await Promise.all([
factDataLoader.load(0),
factDataLoader.load(1),
]));
```
That isn't actually infinitely recursive, but because `0` and `1` end up in the same batch, and `1` depends on `0`, and the result of `0` can't get to the computation around `1` because they're waiting on the same batch... this ends up hanging too. This is basically the same issue, but it's *really* hard to debug!
This example might look contrived, but this hit me in real-world code. My data loaders do data fetching and complex privacy checks. I have arbitrarily-nested posts, and you can only see a post if you can load the post's parent. If you try to load a post and its parent in the same batch of a data loader, it hangs without any error or warning!
Contributor guide
Assessment
This issue has not been assessed yet.