billmalarky / react-native-queue

A React Native Job Queue
MIT License
795 stars 159 forks source link

Job lifecycle always leads to `onFailed` event (instead of `onSuccess`)? #83

Open adbalits opened 3 years ago

adbalits commented 3 years ago

Hello, great library, but I've been working on getting an example running inside my App.tsx and I've noticed that for some reason my "exampleJob" will always end with the onFailed event rather than onSuccess.

Here's the code...

// inside App.tsx...
let [queue,setQueue] = useState<any>(null);
let [queueReady,setQueueReady] = useState(false);

const initQueue = async () => {
    if(queue){
        //
        // Queue has already been created, just make sure it's running.
        //
        queue.start();
        return;
    }

    //
    // Create the queue.
    //
    let q = await queueFactory();

    //
    // Add worker for exampleJob.
    //
    let jobName = "exampleJob";
    const handleJob = async (id, payload) => {
        console.log(`QueueService::${jobName}Worker::ENTER`, {id, payload});
        // do nothing for now
        console.log(`QueueService::${jobName}Worker::EXIT`, {id, payload});
    };
    let workerOptions: WorkerOptions = {
        onComplete: async (id, payload) => {
            console.log(`App::Queue::${jobName}::onComplete::${Date.now()}`, {id,payload});
        },
        onFailed: async (id, payload) => {
            console.log(`App::Queue::${jobName}::onFailed::${Date.now()}`, {id,payload});
        },
        onSuccess: async (id, payload) => {
            console.log(`App::Queue::${jobName}::onSuccess::${Date.now()}`, {id,payload});
        },
        onStart: async (id, payload) => {
            console.log(`App::Queue::${jobName}::onStart::${Date.now()}`, {id,payload});
        },
    };
    q.addWorker(jobName, handleJob, workerOptions);

    //
    // Start the queue and setState.
    // 
    q.start();
    setQueue(q);
    setQueueReady(true);
};

/**
 * Boot the queue.
 */
useEffect(() => {
    initQueue();
},[]);

/**
 * Run an exampleJob when the queue is ready.
 */
 useEffect(() => {
    if(!queueReady){
        // queue not ready, do not proceed
        return;
    }

    //
    // create job
    //
    let jobName = "exampleJob";
    let jobData = {
        emailAddress: 'foo@bar.com',
        randomData: {
            random: 'object',
            of: 'arbitrary data'
        }
    };
    let jobOpts: JobOptions = {
        attempts: 1,
    };
    queue.createJob(jobName, jobData, jobOpts, true);
}, [queueReady]);

And here's the output...

App::Queue::sendCookie::onStart::1633993068497 {id: "79bdd77e-ea42-4c4b-8b78-f80cda245c07", payload: {…}}
App.tsx:92 QueueService::exampleJobWorker::ENTER {id: "79bdd77e-ea42-4c4b-8b78-f80cda245c07", payload: {…}}
App.tsx:93 QueueService::exampleJobWorker::EXIT {id: "79bdd77e-ea42-4c4b-8b78-f80cda245c07", payload: {…}}
App.tsx:81 App::Queue::sendCookie::onFailed::1633993068502 {id: "79bdd77e-ea42-4c4b-8b78-f80cda245c07", payload: {…}}
App.tsx:78 App::Queue::sendCookie::onComplete::1633993068502 {id: "79bdd77e-ea42-4c4b-8b78-f80cda245c07", payload: {…}}

I've tried to figure out what leads to onFailed vs onSuccess but I haven't had any luck. Appreciate any advice.

adbalits commented 3 years ago

I have done some investigation. The reason the job triggers the onFailed lifecycle event is because this error gets triggered during execution of the job:

TypeError: Cannot read property 'ok' of undefined
    at Queue._callee5$ (Queue.js:329)
    at tryCatch (runtime.js:63)
    at Generator.invoke [as _invoke] (runtime.js:294)
    at Generator.next (runtime.js:119)
    at fulfilled (Queue.js:10)
    at tryCallOne (core.js:37)
    at core.js:123
    at JSTimers.js:270
    at _callTimer (JSTimers.js:123)
    at _callImmediatesPass (JSTimers.js:177)

Still looking into why that happens.

adbalits commented 3 years ago

Update: it was this line in the processJob function of Queue.js that caused the runtime error which led to the onFailed event...

if (!executionResult.ok) throw new Error('Execution failure'); // here we catch http errors

I modified my job handler to do the following:

const handleJob = async (id, payload) => {
        console.log(`QueueService::${jobName}Worker::ENTER`, {id, payload});
        // do nothing for now
        console.log(`QueueService::${jobName}Worker::EXIT`, {id, payload});
        return {ok:true};
    };

And now the onSuccess lifecycle event gets triggered instead of onFailed.

I will leave the issue open because this should really be explained in the README.