Vue Batch Runner Component
Develop a Vue.js component that allows users to define, execute, and monitor a series of tasks (a "batch"). This component will be useful for managing sequential or parallel operations within a web application, such as data processing pipelines, form submissions, or background jobs.
Problem Description
Your task is to create a Vue.js component named BatchRunner. This component should provide a user interface for:
- Defining Tasks: Users should be able to add individual tasks to a batch. Each task should have a unique identifier (e.g., a string name) and a function that represents the operation to be performed.
- Configuring Execution: Users should be able to configure how the batch of tasks is executed, specifically choosing between sequential and parallel execution.
- Initiating Execution: A button to start the batch run.
- Monitoring Progress: Display the status of each individual task (e.g., 'Pending', 'Running', 'Success', 'Failed') and the overall batch progress.
- Displaying Results: Show the output or result of successful tasks and any error messages from failed tasks.
Key Requirements:
- The component should accept an array of task definitions as a prop. Each task definition should include at least:
id: A unique string identifier for the task.name: A human-readable name for the task.run: An asynchronous function (async () => Promise<any>) that performs the task's operation. This function should be able to throw an error on failure.
- The component should manage the state of each task (pending, running, success, failed).
- The component should allow the user to select between "Sequential" and "Parallel" execution modes.
- When "Sequential" mode is selected, tasks must be executed one after another, only starting the next task once the previous one has completed (either successfully or with an error).
- When "Parallel" mode is selected, all tasks should be initiated concurrently. The component should still report the success or failure of each individual task.
- The UI should clearly indicate the current status of each task and the overall progress of the batch.
- The component should emit an event when the entire batch has completed (all tasks have finished, regardless of individual success or failure). This event should pass the results (or errors) of all tasks.
Expected Behavior:
- Initially, all tasks are in a 'Pending' state.
- Upon clicking the "Run Batch" button, the selected execution mode dictates the order of task initiation.
- Task statuses should update in real-time as they are executed.
- If a task fails in sequential mode, subsequent tasks should not start.
- If a task fails in parallel mode, other running tasks should continue.
- The final emitted event should contain a summary of all task outcomes.
Edge Cases:
- What happens if a task's
runfunction returns a non-Promise value? (Assume it should be treated as a resolved Promise). - What happens if the
runfunction throws an error synchronously? - What if the
BatchRunnercomponent is updated with new task definitions while a batch is running? (For this challenge, assume the task list is static once the component mounts. You can mention this as a potential extension). - Empty batch: What if no tasks are provided?
Examples
Example 1: Sequential Execution
Input (Prop: tasks)
[
{ id: 'task1', name: 'Fetch User Data', run: async () => { await new Promise(resolve => setTimeout(resolve, 1000)); return { userId: 123, name: 'Alice' }; } },
{ id: 'task2', name: 'Process Data', run: async () => { await new Promise(resolve => setTimeout(resolve, 500)); return { processed: true }; } },
{ id: 'task3', name: 'Save Results', run: async () => { await new Promise(resolve => setTimeout(resolve, 750)); return { saved: true }; } }
]
User Interaction:
- Selects "Sequential" execution mode.
- Clicks "Run Batch".
Expected UI State (during execution):
- Task 1: 'Running'
- Task 2: 'Pending'
- Task 3: 'Pending'
After Task 1 completes successfully:
- Task 1: 'Success' (with output { userId: 123, name: 'Alice' })
- Task 2: 'Running'
- Task 3: 'Pending'
After Task 2 completes successfully:
- Task 1: 'Success'
- Task 2: 'Success' (with output { processed: true })
- Task 3: 'Running'
After Task 3 completes successfully:
- Task 1: 'Success'
- Task 2: 'Success'
- Task 3: 'Success' (with output { saved: true })
Emitted Event (batch-complete) Output:
{
"task1": { status: "success", result: { userId: 123, name: 'Alice' } },
"task2": { status: "success", result: { processed: true } },
"task3": { status: "success", result: { saved: true } }
}
Example 2: Parallel Execution with a Failure
Input (Prop: tasks)
[
{ id: 'taskA', name: 'Download File', run: async () => { await new Promise(resolve => setTimeout(resolve, 1500)); return { fileSize: '10MB' }; } },
{ id: 'taskB', name: 'Validate File', run: async () => { await new Promise(resolve => setTimeout(resolve, 800)); throw new Error('Invalid checksum'); } },
{ id: 'taskC', name: 'Upload Log', run: async () => { await new Promise(resolve => setTimeout(resolve, 1200)); return { uploaded: true }; } }
]
User Interaction:
- Selects "Parallel" execution mode.
- Clicks "Run Batch".
Expected UI State (during execution):
- Task A: 'Running'
- Task B: 'Running'
- Task C: 'Running'
After Task B fails and Task A and C complete:
- Task A: 'Success' (with output { fileSize: '10MB' })
- Task B: 'Failed' (with error message 'Invalid checksum')
- Task C: 'Success' (with output { uploaded: true })
Emitted Event (batch-complete) Output:
{
"taskA": { status: "success", result: { fileSize: '10MB' } },
"taskB": { status: "failed", error: "Invalid checksum" },
"taskC": { status: "success", result: { uploaded: true } }
}
Constraints
- The
tasksprop will be an array of objects, where each object conforms to the structure:{ id: string; name: string; run: () => Promise<any>; }. - The
idproperty for each task will be unique within thetasksarray. - The
runfunction for each task will always return a Promise. - The
runfunction may resolve with any type of value or reject with anErrorobject. - The component should be reactive and update the UI as task statuses change.
Notes
- Consider using
Promise.allfor parallel execution andasync/awaitwith a loop for sequential execution. - You'll need to manage an internal state for each task, including its ID, name, current status, and its result or error.
- The UI should be clear and provide visual feedback on the progress. You might consider using progress bars or simple status text.
- Think about how you will handle the asynchronous nature of task execution to update the UI correctly.
- For the
batch-completeevent, the payload should be an object where keys are task IDs and values contain the status, result, or error for that task.