Running asnyc function synchronously

103 Views Asked by At

I'm pretty new to JS. I'm using a third-party library that has an async callback. The problem is that I need to run through the function in its entirety before processing the next callback. I'm using an upload protocol called tus.io and need to process one upload at a time.

async onUploadCreate(req, res, uploadMetadata) {

    /* I need to check the metadata is valid by using an internal js file */
    //...

    /* Then I need to check the user is logged in by calling a third-party endpoint using axios*/
    //...

    /* Then I check the Mongo db for existing uploadId
    //...
        // if it's not there, create some entries in another db and add the uploadId to mongo
        //If it is there, get some IDs in mongo, which I append to another db
}

As you can see, I need to do a fair bit. I do this because in tus, there is no concept of an upload session; each file comes in an independent upload. I've been testing it by uploading one file at a time. When i use multiple files it's all over the place.

Is there a way I can achieve this in JavaScript? I know this could have a performance impact, so I'm open to suggestions on how else I could achieve this.


EDIT: as per the comments suggest, I've tried awaiting the functions that use axios and the mongo lib but this doesn't seem to make a difference. This is the complete function call:

async onUploadCreate(req, res, upload) {
        /* Check the metadata */
        const {ok, expected} = await common.validateMetadata(upload);
        if (!ok) {
            const body = `Expected "${expected}" in "Upload-Metadata" but received "${upload.metadata}"`;
            throw {status_code: 500, body};
        } else
        logger.info(`Metadata is ok!`);

        /* Check the user is logged in */
        const userAuthorised = await catalogue.getSession(upload.metadata.userSession);
        if (!userAuthorised) {
            const body = `User not authorised`;
            logger.info(`User with session id: "${upload.metadata.userSession}" not authed`);
            throw {status_code: 401, body};
        } else
            logger.info(`User with session id: "${upload.metadata.userSession}" is logged in`);

        /* Create the items in the catalogue and mongo db for tracking upload session*/
        // check the mongo db for existing uploadId
        const result =  await mongo.getUploadIdInDB(upload.metadata.uploadId);
        if (result == null) {
            logger.info(`Upload ID: "${upload.metadata.uploadId}" not found in mongodb`)
            // create a dataset in catalogue
            let dataset = await catalogue.createDataset(upload.metadata);
            // then create the datafiles in catalogue
            let datafile = await catalogue.createDatafile(dataset, upload.id, upload.size, upload.metadata);
            // then add the id in mongo
            await mongo.createUpload(upload.metadata, dataset, datafile)
        }
        else {
            logger.info(`Upload ID: "${upload.metadata.uploadId}" found in mongodb!`)
            // create a new datafile to go this dataset
            let datafile = await catalogue.createDatafile(result.datasetId[0], upload.id, upload.size, upload.metadata);
            // then add the id of the nre datafile to the upload entry in mongo
            await mongo.appendToUpload( result.datasetId, datafile)
        }
        logger.info(`Done processing upload file`)
        return res;
    },

For example the output I get is:

info: Metadata is ok! {"service":"upload-service"}
info: Metadata is ok! {"service":"upload-service"}
info: User with session id: "bb6190fb-369b-406e-8b64-b38bef644df6" is logged in {"service":"upload-service"}
info: User with session id: "bb6190fb-369b-406e-8b64-b38bef644df6" is logged in {"service":"upload-service"}
....

where id expect them to be interlaced

1

There are 1 best solutions below

1
WhatTheWhat On

Because the call is an async callback that I don't have access to, I can't await it. The answer was to dissolve the app’s responsibility to store any state, pushing any creation of database objects upstream to the front end or another service. This only meant the UI had to make 2 consecutive calls instead of one.