#How to return a value from a Promise while having some functionality after?

1 messages · Page 1 of 1 (latest)

mortal moon
#

I'm just trying my luck here because I didn't get an answer in about every other JS thread I could think of.

I am trying to make a queue system where my app can handle 1 job at a time. The jobs can come from different queues where users have to wait for the previous user before their job can be picked up. The previous user can either send a signal they are "done" in 30 seconds after their job finished, or the signal will be sent automatically after 30 seconds so that the next user in that queue has a chance for their job to be picked up. I am trying to achieve the functionality I added in comments:

enum Title {
  A,
  B,
}

const createQueue = () => {
  let tailPromise = Promise.resolve();

  return {
    add: (job: (...args: unknown[]) => Promise<void>) => {
      const promise = tailPromise.then(job);
      tailPromise = promise;

      return promise;
    },
  };
};

export const createTitleQueueManager = () => {
  const queue = createQueue();

  const queues = {
    [Title.A]: createQueue(),
    [Title.B]: createQueue(),
  };

  return {
    requestTitle: async (title: Title, signal: AbortSignal) => {
      let success = false;

      const cancelled = new Promise((resolve) => {
        signal.addEventListener("abort", resolve, { once: true });
      });

      await queues[title].add(async () => {
        await queue.add(async () => {
          await setTimeout(5_000);

          success = true;
        });

        // Want to return the success status to the caller here...

        // Then wait for the caller to send an abort signal before 30 seconds
        // Or resolve after 30 seconds if no signal was sent
        await Promise.race([cancelled, setTimeout(30_000)]);
      });

      // Don't want to return success here because Promise.race already happened
      return { success };
    },
  };
}

The reason I'd like to achieve this is so that I can have this usage at the caller side: https://sourceb.in/lEhsIvnhAb

viscid needle
#

I think you're going to need to not use async/await for all of this.

#

At the least will probably need some manual .then chaining; may end up needing to make a manual promise constructor.

mortal moon
#

Please share if you have a clear picture on it, I tunnel visioned on getting the functionality in the first place

gloomy pumice
#

@mortal moon something like this maybe

let resolve, reject
const promise = new Promise<{ success: boolean }>((ret, err) => {
  resolve = ret
  reject = err
})
await queues[title].add(async () => {
  await Promise.race([cancelled, setTimeout()]).then(resolve).catch(reject)
})
return promise
mortal moon
#

Basically looking for this order of execution

#

If 4 fails it wouldn't return true for success

viscid needle
#

So you'd put resolve({success: true}) when you have the commenet about where you want to return to the user.

mortal moon
#

But then it does Promise.race without the caller side knowing if queues[title].add was succesful or not

#

So the timer they get to cancel it wouldn't be useful

viscid needle
#

The race would have to go sometime before you await, yeah.

mortal moon
#

Yes but that should only happen when 4 is succesful 😅

viscid needle
#

I don't think I really understand what you're going for here.

mortal moon
#

The right snippet shows the use case kind of along with the story

Let's say 3 users request a title
User 1 - Title A
User 2 - Title A
User 3 - Title B

The app can only hand out 1 at a time and users who request one end up in a queue for their specific title request. With this scenario
User 1 waits for title handout, then gets 30 seconds to keep it or cancel it to allow user 2 to get it
User 2 waits for completion of user 1
User 3 doesn't have to wait for completion, only for title handout

#

So order of users getting a title is User 1 > User 3 > User 2

viscid needle
#

@mortal moon A promise on its own is a one-way pipe; the consumer of a promise on its own isn't going to be able to communicate anything back.

mortal moon
#

What can I use here instead? 😅 I only care about the functionality to be honest

viscid needle
#

It could be a promise for a function that the user can call when they're "done", I guess.

#

(But there'd be no way to guarantee that it's called at the right time)

mortal moon
#

Maybe this whole promise thing just isn't the right choice

#

Unless I'm fine with putting everything inside the callbacks