0

I have a list of 30 objects for which I need to call API. I then add the result of all API calls and return as answer. But it gives 503 error after few calls.

override suspend fun getScoreboard(docId: String): ScoreboardResult {
        val scoreboardResult = ScoreboardResult()
        try {
            withContext(Dispatchers.IO) {
                val cfHandles = getCfHandles(docId = docId)
                val contests = getContests(docId = docId).split(";")
                Log.d(TAG, "contests size = ${contests.size}  ===>  $contests")
                Log.d(TAG, Thread.currentThread().toString())
                for(contest in contests) {
                    val options = hashMapOf("contestId" to contest, "handles" to cfHandles)
                    Log.d(TAG, "Doing contest: $contest")
                    lateinit var contestScore: PartiesScore
                    ////delay(1500)//todo: Avoid using this delay
                    launch {
                        Log.d(TAG, Thread.currentThread().toString())
                        contestScore = getPartiesScore(options= options)//suspend function (Api call)
                        if (contestScore.status == Constants.CF_API_SUCCESS_STATUS) {
                            Log.d(TAG, "Success $contest")
                            scoreboardResult.updateScore(contestScore.result.rows)
                        } else {
                            throw (CustomException(message = "Failed at contest: $contest"))
                        }
                    }
                }
            }
            Log.d(TAG, "Everything went well")
            return scoreboardResult
        } catch (exception: Exception) {
            Log.d(TAG, "Something bad happened : ${exception.message}")
            scoreboardResult.exception = exception
            return scoreboardResult
        }
    }

This is my logcat:---

18:20:51.491  D  contests size = 30  ===\>  \[1711, 1714, 1713, 1712, 1722, 1717, 1726, 1729, 1733, 1738, 1737, 1736, 1741, 1742, 1746, 1743, 1732, 1759, 1761, 1760, 1758, 1764, 1771, 1766, 1762, 1767, 1774, 1772, 1770, 1731\]
18:20:51.491  D  Thread\[DefaultDispatcher-worker-2,5,main\]
18:20:51.492  D  Doing contest: 1711
18:20:51.493  D  Doing contest: 1714
18:20:51.494  D  Thread\[DefaultDispatcher-worker-3,5,main\]
18:20:51.494  D  Doing contest: 1713
18:20:51.495  D  Thread\[DefaultDispatcher-worker-1,5,main\]
18:20:51.496  D  Doing contest: 1712
18:20:51.496  D  Thread\[DefaultDispatcher-worker-4,5,main\]
18:20:51.497  D  Doing contest: 1722
18:20:51.497  D  Thread\[DefaultDispatcher-worker-7,5,main\]
18:20:51.498  D  Doing contest: 1717
18:20:51.498  D  Thread\[DefaultDispatcher-worker-6,5,main\]
18:20:51.499  D  Doing contest: 1726
18:20:51.501  D  Thread\[DefaultDispatcher-worker-5,5,main\]
18:20:51.502  D  Doing contest: 1729
18:20:51.503  D  Doing contest: 1733
18:20:51.503  D  Thread\[DefaultDispatcher-worker-10,5,main\]
18:20:51.503  D  Thread\[DefaultDispatcher-worker-8,5,main\]
18:20:51.503  D  Doing contest: 1738
18:20:51.503  D  Thread\[DefaultDispatcher-worker-11,5,main\]
18:20:51.504  D  Doing contest: 1737
18:20:51.504  D  Thread\[DefaultDispatcher-worker-9,5,main\]
18:20:51.504  D  Doing contest: 1736
18:20:51.504  D  Thread\[DefaultDispatcher-worker-13,5,main\]
18:20:51.504  D  Doing contest: 1741
18:20:51.505  D  Thread\[DefaultDispatcher-worker-12,5,main\]
18:20:51.506  D  Doing contest: 1742
18:20:51.506  D  Thread\[DefaultDispatcher-worker-14,5,main\]
18:20:51.511  D  Doing contest: 1746
18:20:51.511  D  Thread\[DefaultDispatcher-worker-4,5,main\]
18:20:51.511  D  Thread\[DefaultDispatcher-worker-14,5,main\]
18:20:51.512  D  Doing contest: 1743
18:20:51.512  D  Doing contest: 1732
18:20:51.513  D  Doing contest: 1759
18:20:51.514  D  Thread\[DefaultDispatcher-worker-7,5,main\]
18:20:51.514  D  Doing contest: 1761
18:20:51.515  D  Thread\[DefaultDispatcher-worker-13,5,main\]
18:20:51.516  D  Doing contest: 1760
18:20:51.516  D  Thread\[DefaultDispatcher-worker-12,5,main\]
18:20:51.516  D  Thread\[DefaultDispatcher-worker-16,5,main\]
18:20:51.517  D  Doing contest: 1758
18:20:51.517  D  Thread\[DefaultDispatcher-worker-4,5,main\]
18:20:51.518  D  Doing contest: 1764
18:20:51.518  D  Thread\[DefaultDispatcher-worker-15,5,main\]
18:20:51.518  D  Thread\[DefaultDispatcher-worker-9,5,main\]
18:20:51.520  D  Doing contest: 1771
18:20:51.521  D  Doing contest: 1766
18:20:51.521  D  Thread\[DefaultDispatcher-worker-12,5,main\]
18:20:51.521  D  Thread\[DefaultDispatcher-worker-15,5,main\]
18:20:51.522  D  Doing contest: 1762
18:20:51.523  D  Doing contest: 1767
18:20:51.523  D  Thread\[DefaultDispatcher-worker-14,5,main\]
18:20:51.525  D  Doing contest: 1774
18:20:51.525  D  Thread\[DefaultDispatcher-worker-9,5,main\]
18:20:51.527  D  Doing contest: 1772
18:20:51.527  D  Doing contest: 1770
18:20:51.527  D  Thread\[DefaultDispatcher-worker-4,5,main\]
18:20:51.528  D  Thread\[DefaultDispatcher-worker-12,5,main\]
18:20:51.528  D  Thread\[DefaultDispatcher-worker-14,5,main\]
18:20:51.528  D  Doing contest: 1731
18:20:51.530  D  Thread\[DefaultDispatcher-worker-2,5,main\]
18:20:52.936  D  Success 1712
18:20:52.964  D  Something bad happened : HTTP 503

If I give some deliberate delay of around 1000-2000ms (just before the launch block) then all the API calls are successful but without delay it gives error. I feel it is too many coroutines being created which causes 503 response.

Since I have 30 contests and using delay for each one of them would give a terrible User Experience.

Is there any way that all API calls are done successfully without using delay ?

3
  • The 503's are probably a limitation with the server (see answer below). But I also see some bugs. All your child coroutines share the contestScore variable. So in any one coroutine, it can write to the variable, and then later when it reads to the variable, it could have been changed by another one of the sibling coroutines. Secondly, ScoreboardResult.updateScore() needs to be internally safe via mutex locking if you're using it this way. If it's not thread safe at all, it will have unexpected results. If synchronized, it will be blocking coroutine threads which is undesirable. Commented Mar 2, 2023 at 14:01
  • Yes I have made the updateScore() function to be synchronized and it is not having any problem so far. Commented Mar 2, 2023 at 14:05
  • I'm saying it's preferable to make them suspending and use a mutex lock so you aren't unnecessarily blocking threads from the coroutine thread pool. But also your contestScore variable is not threadsafe. Commented Mar 2, 2023 at 14:24

1 Answer 1

0

It is not a good practices to have a loop and start a lot of requests at the same time. 503 means, that the server is overloading or blocking your calls in some way.

If you have access to the API you should handle this request with just one call where you transmit all your options in one single option and the API should then return an array with all your scores.

Sign up to request clarification or add additional context in comments.

2 Comments

Unfortunately the API endpoint is such that it only provides one contest score at a time. Meaning for 'n' contests, I need to call it 'n' times.
I guess you have to deal with the server limitations and use the smallest delay that is possible. Bad API requires bad client solutions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.