Skip to content

Add Github Actions #1

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

Merged
merged 18 commits into from
Apr 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .babelrc

This file was deleted.

22 changes: 22 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Node.js CI
on: push

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]

steps:
- uses: actions/checkout@v3

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'

- run: yarn install
- run: yarn run lint
- run: yarn run test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/node_modules
/coverage
/.idea
/reactNativeQueue.realm*
/reactNativeQueue.realm*
*.iml
25 changes: 0 additions & 25 deletions .travis.yml

This file was deleted.

49 changes: 4 additions & 45 deletions Models/Queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
* Queue Job Realm Schema defined in ../config/Database
*
*/

import Database from '../config/Database';
import uuid from 'react-native-uuid';
import Worker from './Worker';
import promiseReflect from 'promise-reflect';


export class Queue {

/**
*
* Set initial class properties.
Expand Down Expand Up @@ -82,7 +79,6 @@ export class Queue {
* @param startQueue - {boolean} - Whether or not to immediately begin prcessing queue. If false queue.start() must be manually called.
*/
createJob(name, payload = {}, options = {}, startQueue = true) {

if (!name) {
throw new Error('Job name must be supplied.');
}
Expand All @@ -109,10 +105,9 @@ export class Queue {
});

// Start queue on job creation if it isn't running by default.
if (startQueue && this.status == 'inactive') {
if (startQueue && this.status === 'inactive') {
this.start();
}

}

/**
Expand All @@ -139,9 +134,8 @@ export class Queue {
* @return {boolean|undefined} - False if queue is already started. Otherwise nothing is returned when queue finishes processing.
*/
async start(lifespan = 0) {

// If queue is already running, don't fire up concurrent loop.
if (this.status == 'active') {
if (this.status === 'active') {
return false;
}

Expand All @@ -160,8 +154,7 @@ export class Queue {
concurrentJobs = await this.getConcurrentJobs();
}

while (this.status == 'active' && concurrentJobs.length) {

while (this.status === 'active' && concurrentJobs.length) {
// Loop over jobs and process them concurrently.
const processingJobs = concurrentJobs.map( job => {
return this.processJob(job);
Expand All @@ -179,11 +172,9 @@ export class Queue {
} else {
concurrentJobs = await this.getConcurrentJobs();
}

}

this.status = 'inactive';

}

/**
Expand All @@ -206,22 +197,16 @@ export class Queue {
* @return {promise} - Promise that resolves to a collection of all the jobs in the queue.
*/
async getJobs(sync = false) {

if (sync) {

let jobs = null;
this.realm.write(() => {

jobs = Array.from(this.realm.objects('Job'));

});

return jobs;

} else {
return Array.from(await this.realm.objects('Job'));
}

}

/**
Expand All @@ -239,11 +224,9 @@ export class Queue {
* @return {promise} - Promise resolves to an array of job(s) to be processed next by the queue.
*/
async getConcurrentJobs(queueLifespanRemaining = 0) {

let concurrentJobs = [];

this.realm.write(() => {

// Get next job from queue.
let nextJob = null;

Expand Down Expand Up @@ -294,9 +277,7 @@ export class Queue {
.sorted([['priority', true], ['created', false]]));

concurrentJobs = reselectedJobs.slice(0, concurrency);

}

});

return concurrentJobs;
Expand All @@ -319,7 +300,6 @@ export class Queue {
* @param job {object} - Job realm model object
*/
async processJob(job) {

// Data must be cloned off the realm job object for several lifecycle callbacks to work correctly.
// This is because realm job is deleted before some callbacks are called if job processed successfully.
// More info: https://github.com/billmalarky/react-native-queue/issues/2#issuecomment-361418965
Expand All @@ -331,27 +311,21 @@ export class Queue {
this.worker.executeJobLifecycleCallback('onStart', jobName, jobId, jobPayload);

try {

await this.worker.executeJob(job);

// On successful job completion, remove job
this.realm.write(() => {

this.realm.delete(job);

});

// Job has processed successfully, fire onSuccess and onComplete job lifecycle callbacks.
this.worker.executeJobLifecycleCallback('onSuccess', jobName, jobId, jobPayload);
this.worker.executeJobLifecycleCallback('onComplete', jobName, jobId, jobPayload);

} catch (error) {

// Handle job failure logic, including retries.
let jobData = JSON.parse(job.data);

this.realm.write(() => {

// Increment failed attempts number
if (!jobData.failedAttempts) {
jobData.failedAttempts = 1;
Expand All @@ -375,7 +349,6 @@ export class Queue {
if (jobData.failedAttempts >= jobData.attempts) {
job.failed = new Date();
}

});

// Execute job onFailure lifecycle callback.
Expand All @@ -386,9 +359,7 @@ export class Queue {
this.worker.executeJobLifecycleCallback('onFailed', jobName, jobId, jobPayload);
this.worker.executeJobLifecycleCallback('onComplete', jobName, jobId, jobPayload);
}

}

}

/**
Expand All @@ -398,34 +369,24 @@ export class Queue {
* If jobName is supplied, only jobs associated with that name
* will be deleted. Otherwise all jobs in queue will be deleted.
*
* @param jobName {string} - Name associated with job (and related job worker).
* @param jobName {string|null} - Name associated with job (and related job worker).
*/
flushQueue(jobName = null) {

if (jobName) {

this.realm.write(() => {

let jobs = Array.from(this.realm.objects('Job')
.filtered('name == "' + jobName + '"'));

if (jobs.length) {
this.realm.delete(jobs);
}

});

} else {
this.realm.write(() => {

this.realm.deleteAll();

});
}

}


}

/**
Expand All @@ -435,10 +396,8 @@ export class Queue {
* @return {Queue} - A queue instance.
*/
export default async function queueFactory() {

const queue = new Queue();
await queue.init();

return queue;

}
18 changes: 1 addition & 17 deletions Models/Worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
* Worker Model
*
*/

export default class Worker {

/**
*
* Singleton map of all worker functions assigned to queue.
Expand Down Expand Up @@ -33,7 +31,6 @@ export default class Worker {
* @param options {object} - Worker options. See README.md for worker options info.
*/
addWorker(jobName, worker, options = {}) {

// Validate input.
if (!jobName || !worker) {
throw new Error('Job name and associated worker function must be supplied.');
Expand Down Expand Up @@ -73,14 +70,12 @@ export default class Worker {
* @return {number}
*/
getConcurrency(jobName) {

// If no worker assigned to job name, throw error.
if (!Worker.workers[jobName]) {
throw new Error('Job ' + jobName + ' does not have a worker assigned to it.');
}

return Worker.workers[jobName].options.concurrency;

}

/**
Expand All @@ -93,7 +88,6 @@ export default class Worker {
* @param job {object} - Job realm model object
*/
async executeJob(job) {

// If no worker assigned to job name, throw error.
if (!Worker.workers[job.name]) {
throw new Error('Job ' + job.name + ' does not have a worker assigned to it.');
Expand All @@ -107,21 +101,16 @@ export default class Worker {
const jobPayload = JSON.parse(job.payload);

if (jobTimeout > 0) {

let timeoutPromise = new Promise((resolve, reject) => {

setTimeout(() => {
reject(new Error('TIMEOUT: Job id: ' + jobId + ' timed out in ' + jobTimeout + 'ms.'));
}, jobTimeout);

});

await Promise.race([timeoutPromise, Worker.workers[jobName](jobId, jobPayload)]);

} else {
await Worker.workers[jobName](jobId, jobPayload);
}

}

/**
Expand All @@ -134,7 +123,6 @@ export default class Worker {
* @param jobPayload {object} - Data payload associated with job.
*/
async executeJobLifecycleCallback(callbackName, jobName, jobId, jobPayload) {

// Validate callback name
const validCallbacks = ['onStart', 'onSuccess', 'onFailure', 'onFailed', 'onComplete'];
if (!validCallbacks.includes(callbackName)) {
Expand All @@ -144,15 +132,11 @@ export default class Worker {
// Fire job lifecycle callback if set.
// Uses a try catch statement to gracefully degrade errors in production.
if (Worker.workers[jobName].options[callbackName]) {

try {
await Worker.workers[jobName].options[callbackName](jobId, jobPayload);
} catch (error) {
console.error(error); // eslint-disable-line no-console
}

}

}

}
}
Loading