All files / ext.wikilambda.app/store/stores queue.js

100% Statements 108/108
100% Branches 14/14
100% Functions 4/4
100% Lines 108/108

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 21x 21x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 13x 13x 15x 15x 103x 103x 103x 103x 103x 103x 103x 103x 103x 103x 13x 13x 13x 13x 13x 13x 13x 11x 11x 13x 13x 2x 2x 13x 13x 13x 13x 13x 13x 13x 13x 13x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 13x 13x 13x 103x 103x  
/*!
 * WikiLambda Vue editor: Handle the request of function calls to the orchestrator. (Pinia)
 *
 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
 * @license MIT
 */
'use strict';
 
const Constants = require( '../../Constants.js' );
 
module.exports = {
	state: {
		activeJob: null,
		delayMs: 200,
		queue: []
	},
 
	getters: {
		/**
		 * Returns next available job to run (must be in a waiting state).
		 *
		 * @param {Object} state
		 * @return {Object} job
		 */
		nextWaitingJob: function ( state ) {
			return state.queue.filter( ( job ) => job.status === Constants.QUEUE_STATUS.WAITING )[ 0 ];
		}
	},
 
	actions: {
		/**
		 * Creates a job and adds it to the queue.
		 * If there is no running job at the moment, initiates
		 * the execution of queue jobs.
		 *
		 * @param {Function} run - job to add to the queue, must return a Promise
		 * @return {Object} job
		 */
		enqueue: function ( run ) {
			let resolver;
			const promise = new Promise( ( resolve, reject ) => {
				resolver = { resolve, reject };
			} );
 
			const job = {
				id: `${ Date.now() }.${ Math.random().toFixed( 6 ).slice( -6 ) }`,
				status: Constants.QUEUE_STATUS.WAITING,
				promise,
				run,
				resolver
			};
 
			// Add job to the state queue
			this.queue.push( job );
 
			// If no active job, start running this one
			if ( !this.activeJob ) {
				this.runJob( job );
			}
 
			return job;
		},
		/**
		 * Runs a job in the queue. Once the job has been run,
		 * it resolves the Promise, removes the job from the queue
		 * and schedules it to run the next job in the queue after
		 * some delay.
		 *
		 * @param {Object} job
		 */
		runJob: function ( job ) {
			// Set job as active job
			this.activeJob = job;
			job.status = Constants.QUEUE_STATUS.PROCESSING;
 
			// Run job run function
			job.run()
				.then( ( result ) => {
					job.status = Constants.QUEUE_STATUS.RESOLVED;
					job.resolver.resolve( result );
				} )
				.catch( ( err ) => {
					job.status = Constants.QUEUE_STATUS.REJECTED;
					job.resolver.reject( err );
				} )
				.finally( () => {
					// Remove from queue when finished
					this.queue = this.queue.filter( ( j ) => j.id !== job.id );
 
					// Schedule the job, after a short delay:
					// * run next job in the queue, or
					// * set activeJob to null if the queue is empty
					setTimeout( () => {
						const nextJob = this.nextWaitingJob;
 
						// If there is no next job, set activeJob to null and exit
						if ( !nextJob ) {
							this.activeJob = null;
							return;
						}
 
						// Else, run next job
						this.runJob( nextJob );
					}, this.delayMs );
				} );
		}
	}
};