Skip to content

Commit

Permalink
Merge pull request #70 from momentohq/chore/resource-exhausted-msg
Browse files Browse the repository at this point in the history
chore: modify resource exhausted message using metadata and add messa…
  • Loading branch information
rishtigupta authored Nov 12, 2024
2 parents 5a103ac + a31b16d commit 6eb2324
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package software.momento.kotlin.sdk


import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@LargeTest
class LimitExceededExceptionTest: BaseAndroidTestClass() {

@Test
fun shouldFailWithResourceExhaustedMessage() = runTest {
val key = "cache";
val value = 'x'.toString().repeat(5_300_000) // 5.3MB

val setResponse = cacheClient.set(cacheName, key, value)
val stringifiedResponse = setResponse.toString()
assert(stringifiedResponse.contains("Request size limit exceeded for this account"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ public object CacheServiceExceptionMapper {
val errorDetails = MomentoTransportErrorDetails(
MomentoGrpcErrorDetails(statusCode, e.message!!, metadata)
)
convertStatusException(e, errorDetails, statusCode)
val errorCause = metadata?.get(Metadata.Key.of("err", Metadata.ASCII_STRING_MARSHALLER))
convertStatusException(e, errorDetails, statusCode, errorCause)
}
else -> UnknownException(SDK_FAILED_TO_PROCESS_THE_REQUEST, e)
}
}

private fun convertStatusException(e: Throwable, errorDetails: MomentoTransportErrorDetails, statusCode: Status.Code): SdkException {
private fun convertStatusException(e: Throwable, errorDetails: MomentoTransportErrorDetails, statusCode: Status.Code, errorCause: String?): SdkException {
return when (statusCode) {
Status.Code.INVALID_ARGUMENT, Status.Code.UNIMPLEMENTED,
Status.Code.OUT_OF_RANGE, Status.Code.FAILED_PRECONDITION -> BadRequestException(
Expand All @@ -52,9 +53,9 @@ public object CacheServiceExceptionMapper {
e, errorDetails
)
Status.Code.UNAUTHENTICATED -> AuthenticationException(e, errorDetails)
Status.Code.RESOURCE_EXHAUSTED -> LimitExceededException(
e, errorDetails
)
Status.Code.RESOURCE_EXHAUSTED -> {
LimitExceededException(errorCause, errorDetails)
}
Status.Code.NOT_FOUND -> NotFoundException(e, errorDetails)
Status.Code.ALREADY_EXISTS -> AlreadyExistsException(e, errorDetails)
Status.Code.UNKNOWN -> UnknownServiceException(e, errorDetails)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,67 @@ package software.momento.kotlin.sdk.exceptions

import software.momento.kotlin.sdk.internal.MomentoTransportErrorDetails

/**
* Requested operation couldn't be completed because system limits were hit.
*/
private enum class LimitExceededMessageWrapper(val message: String) {
TOPIC_SUBSCRIPTIONS_LIMIT_EXCEEDED("Topic subscriptions limit exceeded for this account"),
OPERATIONS_RATE_LIMIT_EXCEEDED("Request rate limit exceeded for this account"),
THROUGHPUT_RATE_LIMIT_EXCEEDED("Bandwidth limit exceeded for this account"),
REQUEST_SIZE_LIMIT_EXCEEDED("Request size limit exceeded for this account"),
ITEM_SIZE_LIMIT_EXCEEDED("Item size limit exceeded for this account"),
ELEMENT_SIZE_LIMIT_EXCEEDED("Element size limit exceeded for this account"),
UNKNOWN_LIMIT_EXCEEDED("Limit exceeded for this account")
}

public class LimitExceededException(
cause: Throwable,
transportErrorDetails: MomentoTransportErrorDetails
errCause: String? = null,
transportErrorDetails: MomentoTransportErrorDetails,
cause: Throwable? = null
) : MomentoServiceException(
MomentoErrorCode.LIMIT_EXCEEDED_ERROR,
MESSAGE,
determineMessageWrapper(errCause, transportErrorDetails),
cause,
transportErrorDetails
) {
private companion object {
const val MESSAGE = "Request rate, bandwidth, or object size exceeded the limits for this account. To resolve this error, reduce your usage as appropriate or contact Momento to request a limit increase."
private fun determineMessageWrapper(
errCause: String?,
transportErrorDetails: MomentoTransportErrorDetails
): String {
// First, determine the message based on `errCause`
errCause?.let {
val lowerCaseErrCause = it.lowercase()

when (lowerCaseErrCause) {
"topic_subscriptions_limit_exceeded" ->
return LimitExceededMessageWrapper.TOPIC_SUBSCRIPTIONS_LIMIT_EXCEEDED.message
"operations_rate_limit_exceeded" ->
return LimitExceededMessageWrapper.OPERATIONS_RATE_LIMIT_EXCEEDED.message
"throughput_rate_limit_exceeded" ->
return LimitExceededMessageWrapper.THROUGHPUT_RATE_LIMIT_EXCEEDED.message
"request_size_limit_exceeded" ->
return LimitExceededMessageWrapper.REQUEST_SIZE_LIMIT_EXCEEDED.message
"item_size_limit_exceeded" ->
return LimitExceededMessageWrapper.ITEM_SIZE_LIMIT_EXCEEDED.message
"element_size_limit_exceeded" ->
return LimitExceededMessageWrapper.ELEMENT_SIZE_LIMIT_EXCEEDED.message
else -> { /* Do nothing */ }
}
}

// If `errCause` is null, fall back to checking transport error details
transportErrorDetails.grpc.details.lowercase().let { details ->
when {
"subscribers" in details -> return LimitExceededMessageWrapper.TOPIC_SUBSCRIPTIONS_LIMIT_EXCEEDED.message
"operations" in details -> return LimitExceededMessageWrapper.OPERATIONS_RATE_LIMIT_EXCEEDED.message
"throughput" in details -> return LimitExceededMessageWrapper.THROUGHPUT_RATE_LIMIT_EXCEEDED.message
"request limit" in details -> return LimitExceededMessageWrapper.REQUEST_SIZE_LIMIT_EXCEEDED.message
"item size" in details -> return LimitExceededMessageWrapper.ITEM_SIZE_LIMIT_EXCEEDED.message
"element size" in details -> return LimitExceededMessageWrapper.ELEMENT_SIZE_LIMIT_EXCEEDED.message
else -> { /* Do nothing */}
}
}

// Default message if no conditions match
return LimitExceededMessageWrapper.UNKNOWN_LIMIT_EXCEEDED.message
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package software.momento.kotlin.sdk

import kotlinx.coroutines.test.runTest
import kotlin.test.Test

class LimitExceededExceptionTest: BaseJvmTestClass() {

@Test
fun shouldFailWithResourceExhaustedMessage() = runTest {
val key = "cache";
val value = 'x'.toString().repeat(5_300_000) // 5.3MB

val setResponse = cacheClient.set(cacheName, key, value)
val stringifiedResponse = setResponse.toString()
assert(stringifiedResponse.contains("Request size limit exceeded for this account"))
}
}

0 comments on commit 6eb2324

Please sign in to comment.