vortexpy 6.2.2__tar.gz → 6.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vortexpy-6.2.2 → vortexpy-6.2.4}/PKG-INFO +1 -1
- {vortexpy-6.2.2 → vortexpy-6.2.4}/pyproject.toml +1 -1
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadResponse.py +60 -17
- vortexpy-6.2.4/vortex/PayloadResponse_test.py +161 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleDocumentConverter.py +6 -2
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/__init__.py +1 -1
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortexpy.egg-info/PKG-INFO +1 -1
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortexpy.egg-info/SOURCES.txt +0 -1
- vortexpy-6.2.2/LICENSE +0 -22
- vortexpy-6.2.2/vortex/PayloadResponse_test.py +0 -42
- {vortexpy-6.2.2 → vortexpy-6.2.4}/README.md +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/TwistedDeferredTimeout.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/run_http_upgraded_websocket_ping_client.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/run_http_upgraded_websocket_ping_server.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/run_http_upgraded_websocket_rpc_test_client.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/run_http_upgraded_websocket_rpc_test_server.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/run_websocket_rpc_test_client.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/run_websocket_rpc_test_server.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/setup_example_logging.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/example/store_and_load_json.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/setup.cfg +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/DataWrapTuple.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/DeferUtil.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/DeferUtil_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/Jsonable.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/MtlsAuthorizedClientRegistry.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/MtlsAuthorizedClientRegistry_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/MtlsServerSslOptions.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/Payload.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadEndpoint.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadEndpointTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadEnvelope.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadFilterKeys.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadIO.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadPriority.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadResponseTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PayloadTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/PerformTestActionTuple.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/SerialiseUtil.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/SerialiseUtil_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TestTuple.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/Tuple.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleAction.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleBson.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleBson_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleDataForTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TuplePerfTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TuplePolymorphicTupleTypeFieldArgTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleRestful.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleRestful_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleSelector.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/TupleTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexAccessControlContextABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexAuthenticatorABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexClientHttp.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexClientHttpTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexClientTcp.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexClientWebsocketFactory.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexConnectionABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexEndpointPermission.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexFactory.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexFactory_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexPayloadProtocol.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexPermission.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexPermissionError.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServer.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServerConnection.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServerConnection_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServerHttpResource.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServerTcp.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServerTcp_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServerWebsocket.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServerWebsocket_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexServer_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexSession.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexSession_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexTcpMemoryLeakPayloadTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexTcpMemoryLeakRawTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexUserDetailsABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexUtil.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexWritePushProducer.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/VortexWritePushProducer_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/data_loader/TupleDataLiveLockManager.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/data_loader/TupleDataLiveLockManager_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/data_loader/TupleDataLoader.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/data_loader/TupleDataLoaderDelegate.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/data_loader/TupleDataLoaderTupleABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/data_loader/TupleDataLoaderTuples.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/data_loader/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/event_bus/TupleChangeEventABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/event_bus/TupleChangeEventBus.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/event_bus/TupleChangeEventBusObserverABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/event_bus/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleActionProcessor.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleActionProcessorProxy.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleActionProcessorTestHandler.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleActionProcessor_shutdown_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleActionProcessor_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleActionPushOffline.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleActionPushOffline_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataAccessGranterABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataActionClient.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataActionClient_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObservableCache.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObservableCache_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObservableHandler.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObservableHandler_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObservableProxyHandler.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObservableProxyHandler_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObservableTestHandler.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataObserverClient.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataOfflineObserverService.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataOfflineObserverService_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/TupleDataProviderABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/VortexJSTupleLoaderTestHandler.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/handler/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/mypy_plugin.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/payload_many_tuples_benchmark_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/py.typed +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/GzippedDataHttpClient.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/GzippedDataHttpClientTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/GzippedPayloadHttpClient.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/RestfulHttpClient.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/RestfulResource.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/restful_http_client_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/restful/restful_resource_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/rpc/RPC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/rpc/RPCTest.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/rpc/RPC_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/rpc/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/sqla_orm/OrmCrudHandler.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/sqla_orm/TupleProviderForDb.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/sqla_orm/VortexTupleJson.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/sqla_orm/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleActionStorageSqlite.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleOfflineStorageNameService.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleOfflineStorageSecureService.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleOfflineStorageSecureService_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleOfflineStorageService.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleStorageServiceABC.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleStorageSqlite.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleStorageSqliteService.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/TupleStorageSqliteService_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/storage/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/tuple_json_schema/__init__.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/tuple_json_schema/constants.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/tuple_json_schema/json_schema_node_tuple.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/tuple_json_schema/tuple_json_schema_builder.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/tuple_json_schema/tuple_json_schema_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/tuple_json_schema/tuple_json_schema_test_tuples.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/tuple_test_fixtures.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/twisted_runtime_metrics.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortex/twisted_runtime_metrics_test.py +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortexpy.egg-info/dependency_links.txt +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortexpy.egg-info/entry_points.txt +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortexpy.egg-info/requires.txt +0 -0
- {vortexpy-6.2.2 → vortexpy-6.2.4}/vortexpy.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vortexpy"
|
|
7
|
-
version = "6.2.
|
|
7
|
+
version = "6.2.4"
|
|
8
8
|
license = {text = "MIT"}
|
|
9
9
|
authors = [{name = "Flying Ion Pty Ltd", email = "contact@flyingion.com"}]
|
|
10
10
|
description = "Flying Ion's observable, routable, data serialisation and transport code."
|
|
@@ -16,6 +16,8 @@ from uuid import uuid4
|
|
|
16
16
|
import pytz
|
|
17
17
|
from twisted.internet import reactor
|
|
18
18
|
from twisted.internet.defer import Deferred
|
|
19
|
+
from twisted.internet.defer import TimeoutError
|
|
20
|
+
from twisted.internet.interfaces import IDelayedCall
|
|
19
21
|
from twisted.python.failure import Failure
|
|
20
22
|
|
|
21
23
|
from vortex.PayloadEndpoint import PayloadEndpoint
|
|
@@ -68,6 +70,7 @@ class PayloadResponse(Deferred):
|
|
|
68
70
|
timeout: Optional[float] = None,
|
|
69
71
|
resultCheck=True,
|
|
70
72
|
logTimeoutException=True,
|
|
73
|
+
retries: Optional[int] = None,
|
|
71
74
|
) -> None:
|
|
72
75
|
"""Constructor
|
|
73
76
|
|
|
@@ -83,9 +86,16 @@ class PayloadResponse(Deferred):
|
|
|
83
86
|
it errback will be called.
|
|
84
87
|
:param logTimeoutException: When True, payload timeouts log at ERROR.
|
|
85
88
|
When False, timeouts log at DEBUG with neutral wording.
|
|
89
|
+
:param retries: The number of times to resend the payload envelope
|
|
90
|
+
when the response times out; None sends once with no
|
|
91
|
+
retries. Requires destVortexName or destVortexUuid.
|
|
86
92
|
"""
|
|
87
93
|
Deferred.__init__(self)
|
|
88
94
|
|
|
95
|
+
assert retries is None or (destVortexName or destVortexUuid), (
|
|
96
|
+
"retries requires destVortexName or destVortexUuid to resend"
|
|
97
|
+
)
|
|
98
|
+
|
|
89
99
|
if not timeout:
|
|
90
100
|
timeout = self.TIMEOUT
|
|
91
101
|
|
|
@@ -99,6 +109,11 @@ class PayloadResponse(Deferred):
|
|
|
99
109
|
payloadEnvelope.filt[self.MESSAGE_ID_KEY] = self._messageId
|
|
100
110
|
self._filt = copy(payloadEnvelope.filt)
|
|
101
111
|
self._destVortexName = destVortexName
|
|
112
|
+
self._destVortexUuid = destVortexUuid
|
|
113
|
+
self._payloadEnvelope = payloadEnvelope
|
|
114
|
+
self._timeout = timeout
|
|
115
|
+
self._retries: Optional[int] = retries
|
|
116
|
+
self._timeoutDelayedCall: Optional[IDelayedCall] = None
|
|
102
117
|
|
|
103
118
|
self._status = self.PROCESSING
|
|
104
119
|
self._date = datetime.now(pytz.utc)
|
|
@@ -107,23 +122,49 @@ class PayloadResponse(Deferred):
|
|
|
107
122
|
self._filt, self._process, requiredPermissions=frozenset()
|
|
108
123
|
)
|
|
109
124
|
|
|
110
|
-
|
|
111
|
-
d: Deferred = payloadEnvelope.toVortexMsgDefer()
|
|
112
|
-
d.addCallback(
|
|
113
|
-
VortexFactory.sendVortexMsg,
|
|
114
|
-
destVortexName=destVortexName,
|
|
115
|
-
destVortexUuid=destVortexUuid,
|
|
116
|
-
)
|
|
117
|
-
d.addErrback(self.errback)
|
|
125
|
+
self._sendVortexMsg()
|
|
118
126
|
|
|
119
127
|
try:
|
|
120
128
|
raise Exception()
|
|
121
129
|
except:
|
|
122
130
|
self._stack = sys.exc_info()[2]
|
|
123
131
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
132
|
+
if retries is None:
|
|
133
|
+
# noinspection PyTypeChecker
|
|
134
|
+
self.addTimeout(timeout, reactor)
|
|
135
|
+
self.addErrback(self._timedOut)
|
|
136
|
+
else:
|
|
137
|
+
self._armTimeout()
|
|
138
|
+
|
|
139
|
+
def _sendVortexMsg(self) -> None:
|
|
140
|
+
if not (self._destVortexName or self._destVortexUuid):
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
d: Deferred = self._payloadEnvelope.toVortexMsgDefer()
|
|
144
|
+
d.addCallback(
|
|
145
|
+
VortexFactory.sendVortexMsg,
|
|
146
|
+
destVortexName=self._destVortexName,
|
|
147
|
+
destVortexUuid=self._destVortexUuid,
|
|
148
|
+
)
|
|
149
|
+
d.addErrback(self.errback)
|
|
150
|
+
|
|
151
|
+
def _armTimeout(self) -> None:
|
|
152
|
+
self._timeoutDelayedCall = reactor.callLater( # type: ignore[attr-defined] # pyright: ignore[reportAttributeAccessIssue]
|
|
153
|
+
self._timeout, self._onTimeout
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def _onTimeout(self) -> None:
|
|
157
|
+
self._timeoutDelayedCall = None
|
|
158
|
+
|
|
159
|
+
if self._retries:
|
|
160
|
+
self._retries -= 1
|
|
161
|
+
self._sendVortexMsg()
|
|
162
|
+
self._armTimeout()
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
failure = Failure(TimeoutError("timed out"))
|
|
166
|
+
self._timedOut(failure)
|
|
167
|
+
self.errback(failure)
|
|
127
168
|
|
|
128
169
|
@classmethod
|
|
129
170
|
def isResponsePayloadEnvelope(cls, payloadEnvelope: PayloadEnvelope):
|
|
@@ -162,6 +203,12 @@ class PayloadResponse(Deferred):
|
|
|
162
203
|
self._endpoint.shutdown()
|
|
163
204
|
self._endpoint = None
|
|
164
205
|
|
|
206
|
+
if self._timeoutDelayedCall is not None:
|
|
207
|
+
# zope Interface methods omit self, which static analysis cannot bind
|
|
208
|
+
if self._timeoutDelayedCall.active(): # pyright: ignore[reportAttributeAccessIssue]
|
|
209
|
+
self._timeoutDelayedCall.cancel() # pyright: ignore[reportAttributeAccessIssue]
|
|
210
|
+
self._timeoutDelayedCall = None
|
|
211
|
+
|
|
165
212
|
if self._destVortexName and vortexName != self._destVortexName:
|
|
166
213
|
logger.debug(
|
|
167
214
|
"Received response from a vortex other than the dest vortex, "
|
|
@@ -175,14 +222,10 @@ class PayloadResponse(Deferred):
|
|
|
175
222
|
logger.error("Received response after timeout for %s" % self._filt)
|
|
176
223
|
return
|
|
177
224
|
|
|
178
|
-
if self._resultCheck and
|
|
225
|
+
if self._resultCheck and payloadEnvelope.result not in (None, True):
|
|
179
226
|
self._status = self.FAILED
|
|
180
227
|
self.errback(
|
|
181
|
-
Failure(
|
|
182
|
-
Exception(payloadEnvelope.result).with_traceback(
|
|
183
|
-
self._stack
|
|
184
|
-
)
|
|
185
|
-
)
|
|
228
|
+
Failure(Exception(payloadEnvelope.result).with_traceback(self._stack))
|
|
186
229
|
)
|
|
187
230
|
|
|
188
231
|
else:
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import MagicMock, patch
|
|
3
|
+
|
|
4
|
+
from twisted.internet.defer import TimeoutError
|
|
5
|
+
from twisted.internet.defer import succeed
|
|
6
|
+
from twisted.python.failure import Failure
|
|
7
|
+
|
|
8
|
+
from vortex.PayloadEnvelope import PayloadEnvelope
|
|
9
|
+
from vortex.PayloadResponse import PayloadResponse
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _FakeDelayedCall:
|
|
13
|
+
def __init__(self, callback) -> None:
|
|
14
|
+
self.callback = callback
|
|
15
|
+
self.cancelled = False
|
|
16
|
+
|
|
17
|
+
def active(self) -> bool:
|
|
18
|
+
return not self.cancelled
|
|
19
|
+
|
|
20
|
+
def cancel(self) -> None:
|
|
21
|
+
self.cancelled = True
|
|
22
|
+
|
|
23
|
+
def fire(self) -> None:
|
|
24
|
+
self.callback()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _FakeReactor:
|
|
28
|
+
def __init__(self) -> None:
|
|
29
|
+
self.delayedCalls: list[_FakeDelayedCall] = []
|
|
30
|
+
|
|
31
|
+
def callLater(self, _seconds: float, callback) -> _FakeDelayedCall:
|
|
32
|
+
call = _FakeDelayedCall(callback)
|
|
33
|
+
self.delayedCalls.append(call)
|
|
34
|
+
return call
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class PayloadResponseLoggingTest(unittest.TestCase):
|
|
38
|
+
@patch("vortex.PayloadResponse.VortexFactory.sendVortexMsg")
|
|
39
|
+
@patch("vortex.PayloadResponse.logger")
|
|
40
|
+
def testTimeoutLogsDebugWhenLogTimeoutExceptionFalse(
|
|
41
|
+
self, mockLogger: MagicMock, _mockSend: MagicMock
|
|
42
|
+
) -> None:
|
|
43
|
+
pr = PayloadResponse(
|
|
44
|
+
PayloadEnvelope(filt={"key": "example"}),
|
|
45
|
+
timeout=30.0,
|
|
46
|
+
logTimeoutException=False,
|
|
47
|
+
)
|
|
48
|
+
pr._timedOut(Failure(TimeoutError("timed out")))
|
|
49
|
+
mockLogger.error.assert_not_called()
|
|
50
|
+
mockLogger.debug.assert_called_once()
|
|
51
|
+
|
|
52
|
+
@patch("vortex.PayloadResponse.VortexFactory.sendVortexMsg")
|
|
53
|
+
@patch("vortex.PayloadResponse.logger")
|
|
54
|
+
def testTimeoutLogsErrorWhenLogTimeoutExceptionTrue(
|
|
55
|
+
self, mockLogger: MagicMock, _mockSend: MagicMock
|
|
56
|
+
) -> None:
|
|
57
|
+
pr = PayloadResponse(
|
|
58
|
+
PayloadEnvelope(filt={"key": "example"}),
|
|
59
|
+
timeout=30.0,
|
|
60
|
+
logTimeoutException=True,
|
|
61
|
+
)
|
|
62
|
+
pr._timedOut(Failure(TimeoutError("timed out")))
|
|
63
|
+
mockLogger.debug.assert_not_called()
|
|
64
|
+
mockLogger.error.assert_called_once()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PayloadResponseRetryTest(unittest.TestCase):
|
|
68
|
+
def setUp(self) -> None:
|
|
69
|
+
self.fakeReactor = _FakeReactor()
|
|
70
|
+
patch("vortex.PayloadResponse.reactor", self.fakeReactor).start()
|
|
71
|
+
self.mockSend: MagicMock = patch(
|
|
72
|
+
"vortex.PayloadResponse.VortexFactory.sendVortexMsg"
|
|
73
|
+
).start()
|
|
74
|
+
patch(
|
|
75
|
+
"vortex.PayloadEnvelope.PayloadEnvelope.toVortexMsgDefer",
|
|
76
|
+
return_value=succeed(b"{}"),
|
|
77
|
+
).start()
|
|
78
|
+
self.addCleanup(patch.stopall)
|
|
79
|
+
|
|
80
|
+
def testTimeoutResendsPayloadAndSucceedsOnLateResponse(self) -> None:
|
|
81
|
+
pr = PayloadResponse(
|
|
82
|
+
PayloadEnvelope(filt={"key": "example"}),
|
|
83
|
+
destVortexName="destVortex",
|
|
84
|
+
timeout=30.0,
|
|
85
|
+
retries=1,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
self.assertEqual(self.mockSend.call_count, 1)
|
|
89
|
+
self.assertEqual(len(self.fakeReactor.delayedCalls), 1)
|
|
90
|
+
|
|
91
|
+
# First attempt times out, the payload is resent and re-armed
|
|
92
|
+
self.fakeReactor.delayedCalls[0].fire()
|
|
93
|
+
|
|
94
|
+
self.assertEqual(self.mockSend.call_count, 2)
|
|
95
|
+
self.assertEqual(len(self.fakeReactor.delayedCalls), 2)
|
|
96
|
+
self.assertEqual(pr.status, PayloadResponse.PROCESSING)
|
|
97
|
+
|
|
98
|
+
# The resent payload receives a response
|
|
99
|
+
results = []
|
|
100
|
+
pr.addCallback(results.append)
|
|
101
|
+
response = PayloadEnvelope(filt={"key": "example"})
|
|
102
|
+
pr._process(response, "vortexUuid", "destVortex")
|
|
103
|
+
|
|
104
|
+
self.assertEqual(pr.status, PayloadResponse.SUCCESS)
|
|
105
|
+
self.assertEqual(results, [response])
|
|
106
|
+
self.assertTrue(self.fakeReactor.delayedCalls[1].cancelled)
|
|
107
|
+
|
|
108
|
+
def testExhaustedRetriesErrbackWithTimedOut(self) -> None:
|
|
109
|
+
pr = PayloadResponse(
|
|
110
|
+
PayloadEnvelope(filt={"key": "example"}),
|
|
111
|
+
destVortexName="destVortex",
|
|
112
|
+
timeout=30.0,
|
|
113
|
+
retries=1,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
failures = []
|
|
117
|
+
pr.addErrback(failures.append)
|
|
118
|
+
|
|
119
|
+
self.fakeReactor.delayedCalls[0].fire()
|
|
120
|
+
self.assertEqual(self.mockSend.call_count, 2)
|
|
121
|
+
self.assertEqual(pr.status, PayloadResponse.PROCESSING)
|
|
122
|
+
|
|
123
|
+
self.fakeReactor.delayedCalls[1].fire()
|
|
124
|
+
|
|
125
|
+
self.assertEqual(self.mockSend.call_count, 2)
|
|
126
|
+
self.assertEqual(pr.status, PayloadResponse.TIMED_OUT)
|
|
127
|
+
self.assertEqual(len(failures), 1)
|
|
128
|
+
self.assertIsInstance(failures[0].value, TimeoutError)
|
|
129
|
+
|
|
130
|
+
def testRetriesRequiresDestinationVortex(self) -> None:
|
|
131
|
+
with self.assertRaises(AssertionError):
|
|
132
|
+
PayloadResponse(
|
|
133
|
+
PayloadEnvelope(filt={"key": "example"}),
|
|
134
|
+
timeout=30.0,
|
|
135
|
+
retries=1,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def testDefaultTimeoutPathDoesNotResend(self) -> None:
|
|
139
|
+
pr = PayloadResponse(
|
|
140
|
+
PayloadEnvelope(filt={"key": "example"}),
|
|
141
|
+
destVortexName="destVortex",
|
|
142
|
+
timeout=30.0,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
failures = []
|
|
146
|
+
pr.addErrback(failures.append)
|
|
147
|
+
|
|
148
|
+
self.assertEqual(self.mockSend.call_count, 1)
|
|
149
|
+
self.assertEqual(len(self.fakeReactor.delayedCalls), 1)
|
|
150
|
+
|
|
151
|
+
# addTimeout cancels the deferred, which errbacks with TimeoutError
|
|
152
|
+
self.fakeReactor.delayedCalls[0].fire()
|
|
153
|
+
|
|
154
|
+
self.assertEqual(self.mockSend.call_count, 1)
|
|
155
|
+
self.assertEqual(pr.status, PayloadResponse.TIMED_OUT)
|
|
156
|
+
self.assertEqual(len(failures), 1)
|
|
157
|
+
self.assertIsInstance(failures[0].value, TimeoutError)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
if __name__ == "__main__":
|
|
161
|
+
unittest.main()
|
|
@@ -421,8 +421,12 @@ class TupleDocumentConverterBase:
|
|
|
421
421
|
return cls._makeError(field_path, str(exc), ValueError)
|
|
422
422
|
return None
|
|
423
423
|
|
|
424
|
-
if isinstance(value, list)
|
|
425
|
-
|
|
424
|
+
if isinstance(value, list):
|
|
425
|
+
if get_origin(typeHint) is list:
|
|
426
|
+
return None
|
|
427
|
+
for unionArg in get_args(typeHint):
|
|
428
|
+
if get_origin(unionArg) is list:
|
|
429
|
+
return None
|
|
426
430
|
|
|
427
431
|
if isinstance(value, dict):
|
|
428
432
|
if get_origin(typeHint) is dict:
|
vortexpy-6.2.2/LICENSE
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2016-2026 Flying Ion Pty Ltd
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
22
|
-
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from unittest.mock import MagicMock, patch
|
|
3
|
-
|
|
4
|
-
from twisted.internet.defer import TimeoutError
|
|
5
|
-
from twisted.python.failure import Failure
|
|
6
|
-
|
|
7
|
-
from vortex.PayloadEnvelope import PayloadEnvelope
|
|
8
|
-
from vortex.PayloadResponse import PayloadResponse
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class PayloadResponseLoggingTest(unittest.TestCase):
|
|
12
|
-
@patch("vortex.PayloadResponse.VortexFactory.sendVortexMsg")
|
|
13
|
-
@patch("vortex.PayloadResponse.logger")
|
|
14
|
-
def testTimeoutLogsDebugWhenLogTimeoutExceptionFalse(
|
|
15
|
-
self, mockLogger: MagicMock, _mockSend: MagicMock
|
|
16
|
-
) -> None:
|
|
17
|
-
pr = PayloadResponse(
|
|
18
|
-
PayloadEnvelope(filt={"key": "example"}),
|
|
19
|
-
timeout=30.0,
|
|
20
|
-
logTimeoutException=False,
|
|
21
|
-
)
|
|
22
|
-
pr._timedOut(Failure(TimeoutError("timed out")))
|
|
23
|
-
mockLogger.error.assert_not_called()
|
|
24
|
-
mockLogger.debug.assert_called_once()
|
|
25
|
-
|
|
26
|
-
@patch("vortex.PayloadResponse.VortexFactory.sendVortexMsg")
|
|
27
|
-
@patch("vortex.PayloadResponse.logger")
|
|
28
|
-
def testTimeoutLogsErrorWhenLogTimeoutExceptionTrue(
|
|
29
|
-
self, mockLogger: MagicMock, _mockSend: MagicMock
|
|
30
|
-
) -> None:
|
|
31
|
-
pr = PayloadResponse(
|
|
32
|
-
PayloadEnvelope(filt={"key": "example"}),
|
|
33
|
-
timeout=30.0,
|
|
34
|
-
logTimeoutException=True,
|
|
35
|
-
)
|
|
36
|
-
pr._timedOut(Failure(TimeoutError("timed out")))
|
|
37
|
-
mockLogger.debug.assert_not_called()
|
|
38
|
-
mockLogger.error.assert_called_once()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if __name__ == "__main__":
|
|
42
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|