Skip to content

Commit

Permalink
fix(core): Wrong ignore of source libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
andreidmt committed Dec 15, 2020
1 parent 4e61243 commit e18b572
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 1 deletion.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ typings/

dist/
bin/
lib/
docs/
.coveralls.yml
tags
Expand Down
93 changes: 93 additions & 0 deletions src/lib/queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { findWith, last, is, isEmpty } from "@asd14/m"
import isDeepEqual from "fast-deep-equal"

/**
* Unique, sequential, promise based queue
*
* @example
* const queue = buildQueue()
*
* queue.enqueue(Users.login, {
* args:{
* body: {email: "[email protected]", password: "secret"}
* }
* })
* .then(...)
* .catch(...)
*
* @returns {object<enqueue, dequeue>}
*/
export const buildQueue = () => {
const jobsList = []
let isProcessing = false

return {
enqueue({ id, fn, args }) {
const runningJob = findWith({
id,
args: source => isDeepEqual(source, args),
})(jobsList)

if (is(runningJob)) {
return runningJob.fnPromise
}

let deferredResolve = null
let deferredReject = null
const fnResultPromise = new Promise((resolve, reject) => {
deferredResolve = resolve
deferredReject = reject
})

// add job at begining of queue
jobsList.unshift({
id,
args,
fn,
fnResultPromise,
onResolve: results => {
deferredResolve(results)
},
onReject: error => {
deferredReject(error)
},
})

// start processing jobs
this.dequeue()

// return promise that will be resolved after fn is called and resolved
return fnResultPromise
},

dequeue() {
const shouldStartRunningJobs = !isProcessing && !isEmpty(jobsList)

if (!shouldStartRunningJobs) {
return undefined
}

const { fn, args, onResolve, onReject } = last(jobsList)

// no jobs will be started until current one finishes
isProcessing = true

return Promise.resolve()
.then(() => {
// Need to remove ourselves before job.fn resolves. If another
// action of the same signature runs right after it will return this
// job because job still exists in queue
jobsList.pop()

return fn(...args)
})
.then(onResolve)
.catch(onReject)
.finally(() => {
// process next in queue
isProcessing = false
this.dequeue()
})
},
}
}
75 changes: 75 additions & 0 deletions src/lib/queue.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* eslint-disable no-loop-func */
import test from "tape"
import { map } from "@asd14/m"

import { buildQueue } from "./queue"

test("Promise Queue - Promise based unique elements queue", t => {
const queue = buildQueue()

let findCountBatch1 = 0
let findDateBatch1 = null
let findCountBatch2 = 0
let findDateBatch2 = null

const jobs = [
// add job with same arguments
...map(() =>
queue.enqueue({
fn: () => {
findCountBatch1++
findDateBatch1 = new Date()

return new Promise(resolve => {
setTimeout(() => {
resolve([{ id: 1, name: "test" }])
}, 100)
})
},
args: [
{
path: "/todos",
query: { limit: 10 },
},
],
})
)([1, 2, 3, 4, 5]),
// add job with different arguments
...map(() =>
queue.enqueue({
fn: () => {
findCountBatch2++
findDateBatch2 = new Date()

return new Promise(resolve => {
setTimeout(() => {
resolve([{ id: 1, name: "test" }])
}, 100)
})
},
args: [
{
path: "/todos",
query: { limit: 20 },
},
],
})
)([1, 2, 3, 4, 5]),
]

Promise.all(jobs).then(() => {
t.equals(
findCountBatch1 === 1 && findCountBatch2 === 1,
true,
"Same signature jobs enqueued at the same times should run once"
)

t.equals(
findDateBatch1 < findDateBatch2,
true,
"Different signature jobs should run sequentially"
)

t.end()
})
})

0 comments on commit e18b572

Please sign in to comment.