|
4 | 4 | "AsyncApiExecutor", |
5 | 5 | "BatchApiExecutor", |
6 | 6 | "TransactionApiExecutor", |
| 7 | + "OverloadControlApiExecutor", |
7 | 8 | ] |
8 | 9 |
|
9 | 10 | from collections import OrderedDict |
|
16 | 17 | AsyncExecuteError, |
17 | 18 | BatchExecuteError, |
18 | 19 | BatchStateError, |
| 20 | + OverloadControlExecutorError, |
19 | 21 | TransactionAbortError, |
20 | 22 | TransactionCommitError, |
21 | 23 | TransactionInitError, |
|
32 | 34 | "AsyncApiExecutor", |
33 | 35 | "BatchApiExecutor", |
34 | 36 | "TransactionApiExecutor", |
| 37 | + "OverloadControlApiExecutor", |
35 | 38 | ] |
36 | 39 |
|
37 | 40 | T = TypeVar("T") |
@@ -428,3 +431,84 @@ def abort(self) -> bool: |
428 | 431 | if resp.is_success: |
429 | 432 | return True |
430 | 433 | raise TransactionAbortError(resp, request) |
| 434 | + |
| 435 | + |
| 436 | +class OverloadControlApiExecutor: |
| 437 | + """Allows setting the maximum acceptable server-side queuing time |
| 438 | + for client requests. |
| 439 | +
|
| 440 | + :param connection: HTTP connection. |
| 441 | + :type connection: arango.connection.BasicConnection | |
| 442 | + arango.connection.JwtConnection | arango.connection.JwtSuperuserConnection |
| 443 | + :param max_queue_time_seconds: Maximum server-side queuing time in seconds. |
| 444 | + :type max_queue_time_seconds: float |
| 445 | + """ |
| 446 | + |
| 447 | + def __init__( |
| 448 | + self, connection: Connection, max_queue_time_seconds: Optional[float] = None |
| 449 | + ) -> None: |
| 450 | + self._conn = connection |
| 451 | + self._max_queue_time_seconds = max_queue_time_seconds |
| 452 | + self._queue_time_seconds = 0.0 |
| 453 | + |
| 454 | + @property |
| 455 | + def context(self) -> str: # pragma: no cover |
| 456 | + return "overload-control" |
| 457 | + |
| 458 | + @property |
| 459 | + def queue_time_seconds(self) -> float: |
| 460 | + """Return the most recent request queuing/de-queuing time. |
| 461 | + Defaults to 0 if no request has been sent. |
| 462 | +
|
| 463 | + :return: Server-side queuing time in seconds. |
| 464 | + :rtype: float |
| 465 | + """ |
| 466 | + return self._queue_time_seconds |
| 467 | + |
| 468 | + @property |
| 469 | + def max_queue_time_seconds(self) -> Optional[float]: |
| 470 | + """Return the maximum server-side queuing time. |
| 471 | +
|
| 472 | + :return: Maximum server-side queuing time in seconds. |
| 473 | + :rtype: Optional[float] |
| 474 | + """ |
| 475 | + return self._max_queue_time_seconds |
| 476 | + |
| 477 | + @max_queue_time_seconds.setter |
| 478 | + def max_queue_time_seconds(self, value: Optional[float]) -> None: |
| 479 | + """Set the maximum server-side queuing time. |
| 480 | + Setting it to None disables the feature. |
| 481 | +
|
| 482 | + :param value: Maximum server-side queuing time in seconds. |
| 483 | + :type value: Optional[float] |
| 484 | + """ |
| 485 | + self._max_queue_time_seconds = value |
| 486 | + |
| 487 | + def execute( |
| 488 | + self, |
| 489 | + request: Request, |
| 490 | + response_handler: Callable[[Response], T], |
| 491 | + ) -> T: |
| 492 | + """Execute an API request and return the result. |
| 493 | +
|
| 494 | + :param request: HTTP request. |
| 495 | + :type request: arango.request.Request |
| 496 | + :param response_handler: HTTP response handler. |
| 497 | + :type response_handler: callable |
| 498 | + :return: API execution result. |
| 499 | + """ |
| 500 | + if self._max_queue_time_seconds is not None: |
| 501 | + request.headers["x-arango-queue-time-seconds"] = str( |
| 502 | + self._max_queue_time_seconds |
| 503 | + ) |
| 504 | + resp = self._conn.send_request(request) |
| 505 | + |
| 506 | + if not resp.is_success: |
| 507 | + raise OverloadControlExecutorError(resp, request) |
| 508 | + |
| 509 | + if "X-Arango-Queue-Time-Seconds" in resp.headers: |
| 510 | + self._queue_time_seconds = float( |
| 511 | + resp.headers["X-Arango-Queue-Time-Seconds"] |
| 512 | + ) |
| 513 | + |
| 514 | + return response_handler(resp) |
0 commit comments