vortexpy 4.3.10__tar.gz → 4.3.11__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.
Files changed (146) hide show
  1. {vortexpy-4.3.10 → vortexpy-4.3.11}/PKG-INFO +1 -1
  2. {vortexpy-4.3.10 → vortexpy-4.3.11}/pyproject.toml +1 -1
  3. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadResponse.py +60 -17
  4. vortexpy-4.3.11/vortex/PayloadResponse_test.py +161 -0
  5. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/__init__.py +1 -1
  6. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortexpy.egg-info/PKG-INFO +1 -1
  7. vortexpy-4.3.10/vortex/PayloadResponse_test.py +0 -42
  8. {vortexpy-4.3.10 → vortexpy-4.3.11}/README.md +0 -0
  9. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/TwistedDeferredTimeout.py +0 -0
  10. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/__init__.py +0 -0
  11. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/run_http_upgraded_websocket_ping_client.py +0 -0
  12. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/run_http_upgraded_websocket_ping_server.py +0 -0
  13. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/run_http_upgraded_websocket_rpc_test_client.py +0 -0
  14. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/run_http_upgraded_websocket_rpc_test_server.py +0 -0
  15. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/run_websocket_rpc_test_client.py +0 -0
  16. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/run_websocket_rpc_test_server.py +0 -0
  17. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/setup_example_logging.py +0 -0
  18. {vortexpy-4.3.10 → vortexpy-4.3.11}/example/store_and_load_json.py +0 -0
  19. {vortexpy-4.3.10 → vortexpy-4.3.11}/setup.cfg +0 -0
  20. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/DataWrapTuple.py +0 -0
  21. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/DeferUtil.py +0 -0
  22. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/DeferUtil_test.py +0 -0
  23. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/Jsonable.py +0 -0
  24. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/MtlsAuthorizedClientRegistry.py +0 -0
  25. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/MtlsAuthorizedClientRegistry_test.py +0 -0
  26. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/MtlsServerSslOptions.py +0 -0
  27. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/Payload.py +0 -0
  28. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadEndpoint.py +0 -0
  29. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadEndpointTest.py +0 -0
  30. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadEnvelope.py +0 -0
  31. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadFilterKeys.py +0 -0
  32. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadIO.py +0 -0
  33. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadPriority.py +0 -0
  34. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadResponseTest.py +0 -0
  35. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PayloadTest.py +0 -0
  36. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/PerformTestActionTuple.py +0 -0
  37. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/SerialiseUtil.py +0 -0
  38. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/SerialiseUtil_test.py +0 -0
  39. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TestTuple.py +0 -0
  40. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/Tuple.py +0 -0
  41. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleAction.py +0 -0
  42. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleBson.py +0 -0
  43. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleBson_test.py +0 -0
  44. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleDataForTest.py +0 -0
  45. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleDocumentConverter.py +0 -0
  46. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TuplePerfTest.py +0 -0
  47. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TuplePolymorphicTupleTypeFieldArgTest.py +0 -0
  48. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleRestful.py +0 -0
  49. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleRestful_test.py +0 -0
  50. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleSelector.py +0 -0
  51. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/TupleTest.py +0 -0
  52. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexABC.py +0 -0
  53. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexAccessControlContextABC.py +0 -0
  54. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexAuthenticatorABC.py +0 -0
  55. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexClientHttp.py +0 -0
  56. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexClientHttpTest.py +0 -0
  57. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexClientTcp.py +0 -0
  58. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexClientWebsocketFactory.py +0 -0
  59. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexConnectionABC.py +0 -0
  60. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexEndpointPermission.py +0 -0
  61. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexFactory.py +0 -0
  62. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexFactory_test.py +0 -0
  63. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexPayloadProtocol.py +0 -0
  64. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexPermission.py +0 -0
  65. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexPermissionError.py +0 -0
  66. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServer.py +0 -0
  67. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServerConnection.py +0 -0
  68. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServerConnection_test.py +0 -0
  69. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServerHttpResource.py +0 -0
  70. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServerTcp.py +0 -0
  71. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServerWebsocket.py +0 -0
  72. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServerWebsocket_test.py +0 -0
  73. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexServer_test.py +0 -0
  74. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexSession.py +0 -0
  75. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexSession_test.py +0 -0
  76. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexTcpMemoryLeakPayloadTest.py +0 -0
  77. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexTcpMemoryLeakRawTest.py +0 -0
  78. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexTest.py +0 -0
  79. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexUtil.py +0 -0
  80. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexWritePushProducer.py +0 -0
  81. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/VortexWritePushProducer_test.py +0 -0
  82. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/data_loader/TupleDataLiveLockManager.py +0 -0
  83. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/data_loader/TupleDataLoader.py +0 -0
  84. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/data_loader/TupleDataLoaderDelegate.py +0 -0
  85. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/data_loader/TupleDataLoaderTupleABC.py +0 -0
  86. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/data_loader/TupleDataLoaderTuples.py +0 -0
  87. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/data_loader/__init__.py +0 -0
  88. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/event_bus/TupleChangeEventABC.py +0 -0
  89. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/event_bus/TupleChangeEventBus.py +0 -0
  90. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/event_bus/TupleChangeEventBusObserverABC.py +0 -0
  91. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/event_bus/__init__.py +0 -0
  92. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleActionProcessor.py +0 -0
  93. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleActionProcessorProxy.py +0 -0
  94. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleActionProcessorTestHandler.py +0 -0
  95. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleActionProcessor_shutdown_test.py +0 -0
  96. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleActionPushOffline.py +0 -0
  97. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleActionPushOffline_test.py +0 -0
  98. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataAccessGranterABC.py +0 -0
  99. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataActionClient.py +0 -0
  100. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObservableCache.py +0 -0
  101. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObservableCache_test.py +0 -0
  102. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObservableHandler.py +0 -0
  103. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObservableHandler_test.py +0 -0
  104. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObservableProxyHandler.py +0 -0
  105. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObservableProxyHandler_test.py +0 -0
  106. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObservableTestHandler.py +0 -0
  107. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataObserverClient.py +0 -0
  108. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/TupleDataProviderABC.py +0 -0
  109. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/VortexJSTupleLoaderTestHandler.py +0 -0
  110. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/handler/__init__.py +0 -0
  111. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/mypy_plugin.py +0 -0
  112. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/payload_many_tuples_benchmark_test.py +0 -0
  113. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/py.typed +0 -0
  114. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/GzippedDataHttpClient.py +0 -0
  115. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/GzippedDataHttpClientTest.py +0 -0
  116. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/GzippedPayloadHttpClient.py +0 -0
  117. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/RestfulHttpClient.py +0 -0
  118. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/RestfulResource.py +0 -0
  119. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/__init__.py +0 -0
  120. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/restful_http_client_test.py +0 -0
  121. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/restful/restful_resource_test.py +0 -0
  122. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/rpc/RPC.py +0 -0
  123. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/rpc/RPCTest.py +0 -0
  124. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/rpc/RPC_test.py +0 -0
  125. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/rpc/__init__.py +0 -0
  126. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/sqla_orm/OrmCrudHandler.py +0 -0
  127. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/sqla_orm/TupleProviderForDb.py +0 -0
  128. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/sqla_orm/VortexTupleJson.py +0 -0
  129. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/sqla_orm/__init__.py +0 -0
  130. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/storage/TupleActionStorageSqlite.py +0 -0
  131. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/storage/TupleStorageSqlite.py +0 -0
  132. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/storage/__init__.py +0 -0
  133. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/tuple_json_schema/__init__.py +0 -0
  134. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/tuple_json_schema/constants.py +0 -0
  135. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/tuple_json_schema/json_schema_node_tuple.py +0 -0
  136. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/tuple_json_schema/tuple_json_schema_builder.py +0 -0
  137. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/tuple_json_schema/tuple_json_schema_test.py +0 -0
  138. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/tuple_json_schema/tuple_json_schema_test_tuples.py +0 -0
  139. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/tuple_test_fixtures.py +0 -0
  140. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/twisted_runtime_metrics.py +0 -0
  141. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortex/twisted_runtime_metrics_test.py +0 -0
  142. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortexpy.egg-info/SOURCES.txt +0 -0
  143. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortexpy.egg-info/dependency_links.txt +0 -0
  144. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortexpy.egg-info/entry_points.txt +0 -0
  145. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortexpy.egg-info/requires.txt +0 -0
  146. {vortexpy-4.3.10 → vortexpy-4.3.11}/vortexpy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vortexpy
3
- Version: 4.3.10
3
+ Version: 4.3.11
4
4
  Summary: Flying Ion's observable, routable, data serialisation and transport code.
5
5
  Author-email: Flying Ion Pty Ltd <contact@flyingion.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vortexpy"
7
- version = "4.3.10"
7
+ version = "4.3.11"
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
- if destVortexName or destVortexUuid:
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
- # noinspection PyTypeChecker
125
- self.addTimeout(timeout, reactor)
126
- self.addErrback(self._timedOut)
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):
@@ -163,6 +204,12 @@ class PayloadResponse(Deferred):
163
204
  self._endpoint.shutdown()
164
205
  self._endpoint = None
165
206
 
207
+ if self._timeoutDelayedCall is not None:
208
+ # zope Interface methods omit self, which static analysis cannot bind
209
+ if self._timeoutDelayedCall.active(): # pyright: ignore[reportAttributeAccessIssue]
210
+ self._timeoutDelayedCall.cancel() # pyright: ignore[reportAttributeAccessIssue]
211
+ self._timeoutDelayedCall = None
212
+
166
213
  if self._destVortexName and vortexName != self._destVortexName:
167
214
  logger.debug(
168
215
  "Received response from a vortex other than the dest vortex, "
@@ -176,14 +223,10 @@ class PayloadResponse(Deferred):
176
223
  logger.error("Received response after timeout for %s" % self._filt)
177
224
  return
178
225
 
179
- if self._resultCheck and not payloadEnvelope.result in (None, True):
226
+ if self._resultCheck and payloadEnvelope.result not in (None, True):
180
227
  self._status = self.FAILED
181
228
  self.errback(
182
- Failure(
183
- Exception(payloadEnvelope.result).with_traceback(
184
- self._stack
185
- )
186
- )
229
+ Failure(Exception(payloadEnvelope.result).with_traceback(self._stack))
187
230
  )
188
231
 
189
232
  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()
@@ -6,4 +6,4 @@
6
6
  # Website : https://flyingion.com
7
7
  # Support : contact@flyingion.com
8
8
 
9
- __version__ = '4.3.10'
9
+ __version__ = '4.3.11'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vortexpy
3
- Version: 4.3.10
3
+ Version: 4.3.11
4
4
  Summary: Flying Ion's observable, routable, data serialisation and transport code.
5
5
  Author-email: Flying Ion Pty Ltd <contact@flyingion.com>
6
6
  License: MIT
@@ -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