-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
176 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from __future__ import annotations | ||
|
||
from abc import ( | ||
ABC, | ||
abstractmethod, | ||
) | ||
from types import TracebackType | ||
|
||
|
||
class AutoCloseable(ABC): | ||
def __enter__(self) -> AutoCloseable: | ||
return self | ||
|
||
@abstractmethod | ||
def close(self) -> None: ... | ||
|
||
def __exit__( | ||
self, | ||
exc_type: type[BaseException] | None, | ||
exc_value: BaseException | None, | ||
traceback: TracebackType | None, | ||
) -> None: | ||
self.close() | ||
|
||
|
||
class Resource(AutoCloseable): | ||
@abstractmethod | ||
def cleanup(self) -> None: ... | ||
|
||
def flush(self) -> None: | ||
pass | ||
|
||
def close(self) -> None: | ||
self.flush() | ||
|
||
|
||
class WithResources(Resource): | ||
@property | ||
@abstractmethod | ||
def resources(self) -> tuple[Resource, ...]: ... | ||
|
||
def flush(self) -> None: | ||
for resource in self.resources: | ||
resource.flush() | ||
|
||
def close(self) -> None: | ||
for resource in self.resources: | ||
resource.close() | ||
|
||
def cleanup(self) -> None: | ||
for resource in self.resources: | ||
resource.cleanup() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
from __future__ import annotations | ||
|
||
__all__ = ("OperationsQueue",) | ||
|
||
from multiprocessing import Queue | ||
from time import monotonic | ||
from typing import ( | ||
TYPE_CHECKING, | ||
Callable, | ||
NamedTuple, | ||
) | ||
|
||
from neptune_scale.core.components.abstract import Resource | ||
from neptune_scale.core.validation import verify_type | ||
|
||
if TYPE_CHECKING: | ||
from threading import RLock | ||
|
||
from neptune_api.proto.neptune_pb.ingest.v1.pub.ingest_pb2 import RunOperation | ||
|
||
|
||
class QueueElement(NamedTuple): | ||
sequence_id: int | ||
occured_at: float | ||
operation: bytes | ||
|
||
|
||
def default_max_size_exceeded_callback(max_size: int, e: BaseException) -> None: | ||
raise ValueError(f"Queue is full (max size: {max_size})") from e | ||
|
||
|
||
class OperationsQueue(Resource): | ||
def __init__( | ||
self, | ||
*, | ||
lock: RLock, | ||
max_size: int = 0, | ||
max_size_exceeded_callback: Callable[[int, BaseException], None] | None = None, | ||
) -> None: | ||
verify_type("max_size", max_size, int) | ||
|
||
self._lock: RLock = lock | ||
self._max_size: int = max_size | ||
self._max_size_exceeded_callback: Callable[[int, BaseException], None] = ( | ||
max_size_exceeded_callback if max_size_exceeded_callback is not None else default_max_size_exceeded_callback | ||
) | ||
|
||
self._sequence_id: int = 0 | ||
self._queue: Queue[QueueElement] = Queue(maxsize=max_size) | ||
|
||
def enqueue(self, *, operation: RunOperation) -> None: | ||
try: | ||
with self._lock: | ||
self._queue.put_nowait(QueueElement(self._sequence_id, monotonic(), operation.SerializeToString())) | ||
self._sequence_id += 1 | ||
except Exception as e: | ||
self._max_size_exceeded_callback(self._max_size, e) | ||
|
||
def cleanup(self) -> None: | ||
pass | ||
|
||
def close(self) -> None: | ||
self._queue.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
MAX_RUN_ID_LENGTH = 128 | ||
MAX_FAMILY_LENGTH = 128 | ||
MAX_QUEUE_SIZE = 32767 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import threading | ||
|
||
from neptune_api.proto.neptune_pb.ingest.v1.pub.ingest_pb2 import RunOperation | ||
|
||
from neptune_scale.core.components.operations_queue import OperationsQueue | ||
|
||
|
||
def test_operations_queue(): | ||
# given | ||
lock = threading.RLock() | ||
queue = OperationsQueue(lock=lock, max_size=0) | ||
|
||
# and | ||
operation = RunOperation() | ||
|
||
# when | ||
queue.enqueue(operation=operation) | ||
|
||
# then | ||
assert queue._sequence_id == 1 | ||
|
||
# when | ||
queue.enqueue(operation=operation) | ||
|
||
# then | ||
assert queue._sequence_id == 2 |