Search code examples
software-designsystem-design

Trigger a function after 5 API calls return (in a distributed context)


My girlfriend was asked the below question in an interview:

We trigger 5 independent APIs simultaneously. Once they have all completed, we want to trigger a function. How will you design a system to do this?

My girlfriend replied she will use a flag variable, but the interviewer was evidently not happy with it.

So, is there a good way in which this could be handled (in a distributed context)? Note that each of the 5 API calls are made by different servers and the function to be triggered is on a 6th server.


Solution

  • If I were asked this, my first thought would be to use promises/futures. The idea behind them is that you can execute time-consuming operations asynchronously and they will somehow notify you when they've completed, either successfully or unsuccessfully, typically by calling a callback function. So the first step is to spawn five asynchronous tasks and get five promises.

    Then I would join the five promises together, creating a unified promise that represents the five separate tasks. In JavaScript I might call Promise.all(); in Java I would use CompletableFuture.allOf().

    I would want to make sure to handle both success and failure. The combined promise should succeed if all of the API calls succeed and fail if any of them fail. If any fail there should be appropriate error handling/reporting. What happens if multiple calls fail? How would a mix of successes and failures be reported? These would be design points to mention, though not necessarily solve during the interview.

    Promises and futures typically have modular layering system that would allow edge cases like timeouts to be handled by chaining handlers together. If done right, timeouts could become just another error condition that would be naturally handled by the error handling already in place.

    This solution would not require any state to be shared across threads, so I would not have to worry about mutexes or deadlocks or other thread synchronization problems.


    She said she would use a flag variable to keep track of the number of API calls have returned.

    One thing that makes great interviewees stand out is their ability to anticipate follow-up questions and explain details before they are asked. The best answers are fully fleshed out. They demonstrate that one has thought through one's answer in detail, and they have minimal handwaving.

    When I read the above I have a slew of follow-up questions:

    • How will she know when each API call has returned? Is she waiting for a function call to return, a callback to be called, an event to be fired, or a promise to complete?
    • How is she causing all of the API calls to be executed concurrently? Is there multithreading, a fork-join pool, multiprocessing, or asynchronous execution?
    • Flag variables are booleans. Is she really using a flag, or does she mean a counter?
    • What is the variable tracking and what code is updating it?
    • What is monitoring the variable, what condition is it checking, and what's it doing when the condition is reached?
    • If using multithreading, how is she handling synchronization?
    • How will she handle edge cases such API calls failing, or timing out?

    A flag variable might lead to a workable solution or it might lead nowhere. The only way an interviewer will know which it is is if she thinks about and proactively discusses these various questions. Otherwise, the interviewer will have to pepper her with follow-up questions, and will likely lower their evaluation of her.

    When I interview people, my mental grades are something like:

    • S — Solution works and they addressed all issues without prompting.
    • A — Solution works, follow-up questions answered satisfactorily.
    • B — Solution works, explained well, but there's a better solution that more experienced devs would find.
    • C — What they said is okay, but their depth of knowledge is lacking.
    • F — Their answer is flat out incorrect, or getting them to explain their answer was like pulling teeth.