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
Completing all concurrent tasks if one errors. #34
Comments
Just wondering why you want that? Shouldn't it just stop if it fails? Not sure if this is enough but you can also handle that yourself if you want a certain task to not stop execution by just implementing the |
Hey @SamVerschueren
What I'm looking for is the red cross if it errors. If I catch it in a The use case is a script I've built that performs actions across a series of modules within a project, such as linting, eg: In this case, they are all running concurrently - and the goal is to get to the end and see a complete set of what passed, and what errored out. I'm thinking maybe a
|
Same here. I'd like to allow https://github.com/okonet/lint-staged to run all linters and then output the results for all of them. Right now if one linter fails, the process will end. See lint-staged/lint-staged#86 I've played around with the context but still could not make this to work as I wish. |
So if I understand correctly, it should be possible to prevent exitting if one task fails and just continue processing all the tasks until the end? Also show the error message under the failed task. I will look into that. |
In case of lint-staged I have nested tasks:
In my case, I want to run all linters (on globs) but stop running tasks of the second level whenever the error occurs. I think this is doable with the |
This is related to #16 I think |
@SamVerschueren - yes to your last comment. That's what I was thinking. @okonet takes it to a more sophisticated level that what I was doing ("turtles all the way down"). Smart. |
Just to make sure before I start implementing this, I think the following implementation should cover all the use cases. Base caseJust a regular list, no nested levels. const list = new Listr([
{
title: 'foo',
task: () => Promise.reject(new Error('bar'))
},
{
title: 'unicorn',
task: () => Promise.reject(new Error('rainbow'))
}
], {
exitOnError: false
}); This would result in
Nested level
const list = new Listr([
{
title: 'foo',
task: () => Promise.reject(new Error('bar'))
},
{
title: 'unicorn',
task: () => new Listr([
{
title: 'rainbow',
task: () => Promise.reject(new Error('unicorn rainbow'))
},
{
title: 'fiz',
task: () => Promise.resolve('biz')
}
])
}
], {
exitOnError: false
});
If however, you only want this on the first level, you would define it like this. const list = new Listr([
{
title: 'foo',
task: () => Promise.reject(new Error('bar'))
},
{
title: 'unicorn',
task: () => new Listr([
{
title: 'rainbow',
task: () => Promise.reject(new Error('unicorn rainbow'))
},
{
title: 'fiz',
task: () => Promise.resolve('biz')
}
], {
exitOnError: true
})
}
], {
exitOnError: false
}); Also the other way around, if you only want this on the second level, you would configure it like this. const list = new Listr([
{
title: 'foo',
task: () => Promise.reject(new Error('bar'))
},
{
title: 'unicorn',
task: () => new Listr([
{
title: 'rainbow',
task: () => Promise.reject(new Error('unicorn rainbow'))
},
{
title: 'fiz',
task: () => Promise.resolve('biz')
}
], {
exitOnError: false
})
}
]); Do I miss something? Is this approach flexible enough to cover all the use cases? |
This is looking good to me. Awesome! |
👍 from me too. Looks great @SamVerschueren! |
I will have a look at it, probably this week. Thanks for the feedback! If anything pops up in your mind, don't hesitate to add a comment :). |
Hey 😄 just wondering if there was a branch or anything I could test this out on - this would be very useful for us. |
I've started working on this so I hope to land this soon. |
Awesome @SamVerschueren! Thank you so much 🙌🏻 |
Magnificent @SamVerschueren!! 🥇 |
Alright, I have an update. I have this working, but it's not working in the following use case. It might be an edge case though but wanted to see what you guys think. const tasks = new Listr([
{
title: 'Foo',
task: () => Promise.reject(new Error('Foo bar'))
},
{
title: 'Bar',
task: () => {
return new Listr([
{
title: 'Foo Bar Subtask 1',
task: () => Promise.reject(new Error('Foo bar baz'))
},
{
title: 'Foo Bar Subtask 2',
task: () => delay(2000)
}
], {concurrent: true, exitOnError: true});
}
}
], {
exitOnError: false
}); So at the first level, So this seems to play nice with serial tasks, but it will cause issues when you start to combine them with concurrent tasks because I don't think there is a way I can halt the execution from the other tasks in the concurrent list. |
@SamVerschueren I don't see the problem (maybe I don't understand). Isn't this how To me, this is acceptable behaviour. The thing I'm interested in from the |
I discussed this with @sindresorhus and we came up with a solution. Promises aren't cancellable, observables are. Because Listr supports observables, cancellation for those should work (to be tested but let's assume it works). We could support an const tasks = new Listr([
{
title: 'Foo',
task: () => Promise.reject(new Error('Foo bar'))
},
{
title: 'Bar',
task: () => {
return new Listr([
{
title: 'Foo Bar Subtask 1',
task: () => Promise.reject(new Error('Foo bar baz'))
},
{
title: 'npm install',
task: (ctx, task) => {
const cp = execa('npm', ['install']);
task.onCancel(() => {
cp.kill();
});
return cp;
}
}
], {exitOnError: true});
}
}
], {
exitOnError: false
}); Feedback more then welcome! |
The tasks don't cancel in the current versions of |
@frederickfogerty Yes they do cancel because when one task throws, either in a subtask or whatever, it boils all the way up to the root and the process exits. I agree, it is an edge case, but it's something I like to think through first. Based on the feedback I can still push what I have now (without cancellation) and create a separate issue and see if people need it and implement it later. |
Oh! Of course, the whole process exits - that's the part I was missing. Personally, I'm happy with pushing what's there now, since it's not actually breaking any existing functionality. If people want to use |
I agree on pushing what you have now and create a separate issue. |
The first part of this feature landed in |
Thanks you so much @SamVerschueren! 🙌 🎉 💪 |
@SamVerschueren I've just tried to integrate it and can't wrap my head on how do I display all errors when all tasks complete. When using default renderer, it just continues silently now, so I was expecting the error argumemt in the |
I'm running a set of tasks concurrently. At the moment, if one of the tasks fails, the whole execution is stopped.
Is it possible to have them all continue to completion, whether failed or passed?
Thanks
The text was updated successfully, but these errors were encountered: