vortexpy 4.3.13__tar.gz → 4.3.14__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.13 → vortexpy-4.3.14}/PKG-INFO +1 -1
  2. {vortexpy-4.3.13 → vortexpy-4.3.14}/pyproject.toml +1 -1
  3. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/__init__.py +1 -1
  4. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/twisted_runtime_metrics.py +105 -60
  5. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/twisted_runtime_metrics_test.py +34 -9
  6. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortexpy.egg-info/PKG-INFO +1 -1
  7. {vortexpy-4.3.13 → vortexpy-4.3.14}/README.md +0 -0
  8. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/TwistedDeferredTimeout.py +0 -0
  9. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/__init__.py +0 -0
  10. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/run_http_upgraded_websocket_ping_client.py +0 -0
  11. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/run_http_upgraded_websocket_ping_server.py +0 -0
  12. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/run_http_upgraded_websocket_rpc_test_client.py +0 -0
  13. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/run_http_upgraded_websocket_rpc_test_server.py +0 -0
  14. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/run_websocket_rpc_test_client.py +0 -0
  15. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/run_websocket_rpc_test_server.py +0 -0
  16. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/setup_example_logging.py +0 -0
  17. {vortexpy-4.3.13 → vortexpy-4.3.14}/example/store_and_load_json.py +0 -0
  18. {vortexpy-4.3.13 → vortexpy-4.3.14}/setup.cfg +0 -0
  19. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/DataWrapTuple.py +0 -0
  20. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/DeferUtil.py +0 -0
  21. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/DeferUtil_test.py +0 -0
  22. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/Jsonable.py +0 -0
  23. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/MtlsAuthorizedClientRegistry.py +0 -0
  24. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/MtlsAuthorizedClientRegistry_test.py +0 -0
  25. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/MtlsServerSslOptions.py +0 -0
  26. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/Payload.py +0 -0
  27. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadEndpoint.py +0 -0
  28. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadEndpointTest.py +0 -0
  29. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadEnvelope.py +0 -0
  30. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadFilterKeys.py +0 -0
  31. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadIO.py +0 -0
  32. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadPriority.py +0 -0
  33. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadResponse.py +0 -0
  34. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadResponseTest.py +0 -0
  35. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadResponse_test.py +0 -0
  36. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PayloadTest.py +0 -0
  37. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/PerformTestActionTuple.py +0 -0
  38. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/SerialiseUtil.py +0 -0
  39. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/SerialiseUtil_test.py +0 -0
  40. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TestTuple.py +0 -0
  41. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/Tuple.py +0 -0
  42. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleAction.py +0 -0
  43. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleBson.py +0 -0
  44. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleBson_test.py +0 -0
  45. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleDataForTest.py +0 -0
  46. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleDocumentConverter.py +0 -0
  47. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TuplePerfTest.py +0 -0
  48. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TuplePolymorphicTupleTypeFieldArgTest.py +0 -0
  49. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleRestful.py +0 -0
  50. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleRestful_test.py +0 -0
  51. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleSelector.py +0 -0
  52. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/TupleTest.py +0 -0
  53. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexABC.py +0 -0
  54. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexAccessControlContextABC.py +0 -0
  55. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexAuthenticatorABC.py +0 -0
  56. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexClientHttp.py +0 -0
  57. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexClientHttpTest.py +0 -0
  58. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexClientTcp.py +0 -0
  59. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexClientWebsocketFactory.py +0 -0
  60. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexConnectionABC.py +0 -0
  61. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexEndpointPermission.py +0 -0
  62. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexFactory.py +0 -0
  63. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexFactory_test.py +0 -0
  64. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexPayloadProtocol.py +0 -0
  65. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexPermission.py +0 -0
  66. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexPermissionError.py +0 -0
  67. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServer.py +0 -0
  68. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServerConnection.py +0 -0
  69. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServerConnection_test.py +0 -0
  70. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServerHttpResource.py +0 -0
  71. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServerTcp.py +0 -0
  72. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServerWebsocket.py +0 -0
  73. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServerWebsocket_test.py +0 -0
  74. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexServer_test.py +0 -0
  75. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexSession.py +0 -0
  76. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexSession_test.py +0 -0
  77. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexTcpMemoryLeakPayloadTest.py +0 -0
  78. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexTcpMemoryLeakRawTest.py +0 -0
  79. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexTest.py +0 -0
  80. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexUtil.py +0 -0
  81. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexUtil_test.py +0 -0
  82. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexWritePushProducer.py +0 -0
  83. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/VortexWritePushProducer_test.py +0 -0
  84. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/data_loader/TupleDataLiveLockManager.py +0 -0
  85. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/data_loader/TupleDataLoader.py +0 -0
  86. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/data_loader/TupleDataLoaderDelegate.py +0 -0
  87. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/data_loader/TupleDataLoaderTupleABC.py +0 -0
  88. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/data_loader/TupleDataLoaderTuples.py +0 -0
  89. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/data_loader/__init__.py +0 -0
  90. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/event_bus/TupleChangeEventABC.py +0 -0
  91. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/event_bus/TupleChangeEventBus.py +0 -0
  92. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/event_bus/TupleChangeEventBusObserverABC.py +0 -0
  93. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/event_bus/__init__.py +0 -0
  94. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleActionProcessor.py +0 -0
  95. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleActionProcessorProxy.py +0 -0
  96. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleActionProcessorTestHandler.py +0 -0
  97. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleActionProcessor_shutdown_test.py +0 -0
  98. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleActionPushOffline.py +0 -0
  99. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleActionPushOffline_test.py +0 -0
  100. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataAccessGranterABC.py +0 -0
  101. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataActionClient.py +0 -0
  102. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObservableCache.py +0 -0
  103. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObservableCache_test.py +0 -0
  104. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObservableHandler.py +0 -0
  105. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObservableHandler_test.py +0 -0
  106. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObservableProxyHandler.py +0 -0
  107. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObservableProxyHandler_test.py +0 -0
  108. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObservableTestHandler.py +0 -0
  109. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataObserverClient.py +0 -0
  110. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/TupleDataProviderABC.py +0 -0
  111. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/VortexJSTupleLoaderTestHandler.py +0 -0
  112. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/handler/__init__.py +0 -0
  113. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/mypy_plugin.py +0 -0
  114. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/payload_many_tuples_benchmark_test.py +0 -0
  115. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/py.typed +0 -0
  116. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/GzippedDataHttpClient.py +0 -0
  117. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/GzippedDataHttpClientTest.py +0 -0
  118. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/GzippedPayloadHttpClient.py +0 -0
  119. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/RestfulHttpClient.py +0 -0
  120. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/RestfulResource.py +0 -0
  121. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/__init__.py +0 -0
  122. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/restful_http_client_test.py +0 -0
  123. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/restful/restful_resource_test.py +0 -0
  124. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/rpc/RPC.py +0 -0
  125. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/rpc/RPCTest.py +0 -0
  126. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/rpc/RPC_test.py +0 -0
  127. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/rpc/__init__.py +0 -0
  128. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/sqla_orm/OrmCrudHandler.py +0 -0
  129. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/sqla_orm/TupleProviderForDb.py +0 -0
  130. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/sqla_orm/VortexTupleJson.py +0 -0
  131. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/sqla_orm/__init__.py +0 -0
  132. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/storage/TupleActionStorageSqlite.py +0 -0
  133. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/storage/TupleStorageSqlite.py +0 -0
  134. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/storage/__init__.py +0 -0
  135. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/tuple_json_schema/__init__.py +0 -0
  136. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/tuple_json_schema/constants.py +0 -0
  137. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/tuple_json_schema/json_schema_node_tuple.py +0 -0
  138. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/tuple_json_schema/tuple_json_schema_builder.py +0 -0
  139. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/tuple_json_schema/tuple_json_schema_test.py +0 -0
  140. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/tuple_json_schema/tuple_json_schema_test_tuples.py +0 -0
  141. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortex/tuple_test_fixtures.py +0 -0
  142. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortexpy.egg-info/SOURCES.txt +0 -0
  143. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortexpy.egg-info/dependency_links.txt +0 -0
  144. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortexpy.egg-info/entry_points.txt +0 -0
  145. {vortexpy-4.3.13 → vortexpy-4.3.14}/vortexpy.egg-info/requires.txt +0 -0
  146. {vortexpy-4.3.13 → vortexpy-4.3.14}/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.13
3
+ Version: 4.3.14
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.13"
7
+ version = "4.3.14"
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."
@@ -6,4 +6,4 @@
6
6
  # Website : https://flyingion.com
7
7
  # Support : contact@flyingion.com
8
8
 
9
- __version__ = '4.3.13'
9
+ __version__ = '4.3.14'
@@ -146,13 +146,20 @@ class TwistedRuntimeMetrics:
146
146
  def snapshotAndResetWindow(cls) -> TwistedRuntimeMetricsSnapshot:
147
147
  return cls._collector()._snapshotAndResetWindow()
148
148
 
149
+ @classmethod
150
+ def snapshotWindow(cls) -> TwistedRuntimeMetricsSnapshot:
151
+ """Snapshot the current window counters without resetting them."""
152
+ return cls._collector()._snapshotWindow()
153
+
149
154
  def _start(self, reactorArg: Any) -> None:
150
155
  if self._started:
151
156
  return
152
157
  from twisted.internet.task import LoopingCall
153
158
 
154
159
  self._windowStartedMonotonic = time.monotonic()
155
- self._nextExpectedMonotonic = time.monotonic() + REACTOR_LAG_TICK_SECONDS
160
+ self._nextExpectedMonotonic = (
161
+ time.monotonic() + REACTOR_LAG_TICK_SECONDS
162
+ )
156
163
  self._loop = LoopingCall(
157
164
  vortexLoopingCallCatchWithMetrics(logger)(self._tickReactorLag)
158
165
  )
@@ -185,9 +192,12 @@ class TwistedRuntimeMetrics:
185
192
  with self._metricsLock:
186
193
  self._loopingCallExceptionCount += 1
187
194
  methodCount = (
188
- self._loopingCallExceptionCountByMethod.get(methodQualname, 0) + 1
195
+ self._loopingCallExceptionCountByMethod.get(methodQualname, 0)
196
+ + 1
197
+ )
198
+ self._loopingCallExceptionCountByMethod[methodQualname] = (
199
+ methodCount
189
200
  )
190
- self._loopingCallExceptionCountByMethod[methodQualname] = methodCount
191
201
  self._loopingCallLastExceptionMethod = methodQualname
192
202
  self._loopingCallLastExceptionFrame = exceptionFrame
193
203
  longestCount = 0
@@ -276,6 +286,20 @@ class TwistedRuntimeMetrics:
276
286
  limitConcurrencyMostQueuedCount,
277
287
  )
278
288
 
289
+ def _snapshotWindow(self) -> TwistedRuntimeMetricsSnapshot:
290
+ from twisted.internet import reactor
291
+
292
+ pool = reactor.getThreadPool() # type: ignore[attr-defined] # pyright: ignore[reportAttributeAccessIssue]
293
+ threadPoolBusy = len(pool.working)
294
+ threadPoolQueued = len(pool.waiters)
295
+
296
+ with self._metricsLock:
297
+ return self._utilBuildSnapshotLocked(
298
+ pool,
299
+ threadPoolBusy,
300
+ threadPoolQueued,
301
+ )
302
+
279
303
  def _snapshotAndResetWindow(self) -> TwistedRuntimeMetricsSnapshot:
280
304
  from twisted.internet import reactor
281
305
 
@@ -284,64 +308,79 @@ class TwistedRuntimeMetrics:
284
308
  threadPoolQueued = len(pool.waiters)
285
309
 
286
310
  with self._metricsLock:
287
- elapsedSeconds = time.monotonic() - self._windowStartedMonotonic
288
- windowSeconds = int(max(1, round(elapsedSeconds)))
289
- (
290
- limitConcurrencyRunning,
291
- limitConcurrencyQueued,
292
- limitConcurrencyMax,
293
- limitConcurrencyLimiterCount,
294
- limitConcurrencySaturatedCount,
295
- limitConcurrencyMostQueuedMethod,
296
- limitConcurrencyMostQueuedCount,
297
- ) = self._snapshotLimitConcurrencyStateLocked()
298
- snapshot = TwistedRuntimeMetricsSnapshot(
299
- threadPoolBusy=threadPoolBusy,
300
- threadPoolQueued=threadPoolQueued,
301
- threadPoolMax=pool.max,
302
- threadedCallCount=self._threadedCallCount,
303
- longestThreadedMethodName=self._longestThreadedMethodName,
304
- longestThreadedMethodMs=self._longestThreadedMethodMs,
305
- longestThreadedMethodFrame=self._longestThreadedMethodFrame,
306
- longestReactorBlockMs=self._longestReactorBlockMs,
307
- longestReactorBlockFrame=self._longestReactorBlockFrame,
308
- loopingCallExceptionCount=self._loopingCallExceptionCount,
309
- loopingCallLongestExceptionMethod=(
310
- self._loopingCallLongestExceptionMethod
311
- ),
312
- loopingCallLastExceptionMethod=(self._loopingCallLastExceptionMethod),
313
- loopingCallLastExceptionFrame=(self._loopingCallLastExceptionFrame),
314
- limitConcurrencyRunning=limitConcurrencyRunning,
315
- limitConcurrencyQueued=limitConcurrencyQueued,
316
- limitConcurrencyMax=limitConcurrencyMax,
317
- limitConcurrencyLimiterCount=limitConcurrencyLimiterCount,
318
- limitConcurrencySaturatedCount=limitConcurrencySaturatedCount,
319
- limitConcurrencyCallCount=self._limitConcurrencyCallCount,
320
- limitConcurrencyCallTimeoutCount=(
321
- self._limitConcurrencyCallTimeoutCount
322
- ),
323
- limitConcurrencyLastCallTimeoutMethodName=(
324
- self._limitConcurrencyLastCallTimeoutMethodName
325
- ),
326
- longestLimitConcurrencyMethodName=(
327
- self._longestLimitConcurrencyMethodName
328
- ),
329
- longestLimitConcurrencyMethodMs=(
330
- self._longestLimitConcurrencyMethodMs
331
- ),
332
- longestLimitConcurrencyQueueWaitMs=(
333
- self._longestLimitConcurrencyQueueWaitMs
334
- ),
335
- longestLimitConcurrencyQueueWaitMethod=(
336
- self._longestLimitConcurrencyQueueWaitMethod
337
- ),
338
- limitConcurrencyMostQueuedMethod=limitConcurrencyMostQueuedMethod,
339
- limitConcurrencyMostQueuedCount=limitConcurrencyMostQueuedCount,
340
- windowSeconds=windowSeconds,
311
+ snapshot = self._utilBuildSnapshotLocked(
312
+ pool,
313
+ threadPoolBusy,
314
+ threadPoolQueued,
341
315
  )
342
316
  self._resetWindowCountersLocked()
343
317
  return snapshot
344
318
 
319
+ def _utilBuildSnapshotLocked(
320
+ self,
321
+ pool: Any,
322
+ threadPoolBusy: int,
323
+ threadPoolQueued: int,
324
+ ) -> TwistedRuntimeMetricsSnapshot:
325
+ """Build one snapshot from current counters; caller holds the lock."""
326
+ elapsedSeconds = time.monotonic() - self._windowStartedMonotonic
327
+ windowSeconds = int(max(1, round(elapsedSeconds)))
328
+ (
329
+ limitConcurrencyRunning,
330
+ limitConcurrencyQueued,
331
+ limitConcurrencyMax,
332
+ limitConcurrencyLimiterCount,
333
+ limitConcurrencySaturatedCount,
334
+ limitConcurrencyMostQueuedMethod,
335
+ limitConcurrencyMostQueuedCount,
336
+ ) = self._snapshotLimitConcurrencyStateLocked()
337
+ return TwistedRuntimeMetricsSnapshot(
338
+ threadPoolBusy=threadPoolBusy,
339
+ threadPoolQueued=threadPoolQueued,
340
+ threadPoolMax=pool.max,
341
+ threadedCallCount=self._threadedCallCount,
342
+ longestThreadedMethodName=self._longestThreadedMethodName,
343
+ longestThreadedMethodMs=self._longestThreadedMethodMs,
344
+ longestThreadedMethodFrame=self._longestThreadedMethodFrame,
345
+ longestReactorBlockMs=self._longestReactorBlockMs,
346
+ longestReactorBlockFrame=self._longestReactorBlockFrame,
347
+ loopingCallExceptionCount=self._loopingCallExceptionCount,
348
+ loopingCallLongestExceptionMethod=(
349
+ self._loopingCallLongestExceptionMethod
350
+ ),
351
+ loopingCallLastExceptionMethod=(
352
+ self._loopingCallLastExceptionMethod
353
+ ),
354
+ loopingCallLastExceptionFrame=(self._loopingCallLastExceptionFrame),
355
+ limitConcurrencyRunning=limitConcurrencyRunning,
356
+ limitConcurrencyQueued=limitConcurrencyQueued,
357
+ limitConcurrencyMax=limitConcurrencyMax,
358
+ limitConcurrencyLimiterCount=limitConcurrencyLimiterCount,
359
+ limitConcurrencySaturatedCount=limitConcurrencySaturatedCount,
360
+ limitConcurrencyCallCount=self._limitConcurrencyCallCount,
361
+ limitConcurrencyCallTimeoutCount=(
362
+ self._limitConcurrencyCallTimeoutCount
363
+ ),
364
+ limitConcurrencyLastCallTimeoutMethodName=(
365
+ self._limitConcurrencyLastCallTimeoutMethodName
366
+ ),
367
+ longestLimitConcurrencyMethodName=(
368
+ self._longestLimitConcurrencyMethodName
369
+ ),
370
+ longestLimitConcurrencyMethodMs=(
371
+ self._longestLimitConcurrencyMethodMs
372
+ ),
373
+ longestLimitConcurrencyQueueWaitMs=(
374
+ self._longestLimitConcurrencyQueueWaitMs
375
+ ),
376
+ longestLimitConcurrencyQueueWaitMethod=(
377
+ self._longestLimitConcurrencyQueueWaitMethod
378
+ ),
379
+ limitConcurrencyMostQueuedMethod=limitConcurrencyMostQueuedMethod,
380
+ limitConcurrencyMostQueuedCount=limitConcurrencyMostQueuedCount,
381
+ windowSeconds=windowSeconds,
382
+ )
383
+
345
384
  def _tickReactorLag(self) -> None:
346
385
  now = time.monotonic()
347
386
  lagMs = (now - self._nextExpectedMonotonic) * 1000.0
@@ -394,7 +433,9 @@ class TwistedRuntimeMetrics:
394
433
  if frame is None:
395
434
  return None
396
435
  for summary in reversed(traceback.extract_stack(frame)):
397
- if TwistedRuntimeMetrics._utilSkipInternalMetricsFrame(summary.filename):
436
+ if TwistedRuntimeMetrics._utilSkipInternalMetricsFrame(
437
+ summary.filename
438
+ ):
398
439
  continue
399
440
  return f"{summary.filename}:{summary.name}:{summary.lineno}"
400
441
  return None
@@ -402,7 +443,9 @@ class TwistedRuntimeMetrics:
402
443
  @staticmethod
403
444
  def _captureWorkerThreadFrame() -> str | None:
404
445
  for summary in reversed(traceback.extract_stack()):
405
- if TwistedRuntimeMetrics._utilSkipInternalMetricsFrame(summary.filename):
446
+ if TwistedRuntimeMetrics._utilSkipInternalMetricsFrame(
447
+ summary.filename
448
+ ):
406
449
  continue
407
450
  return f"{summary.filename}:{summary.name}:{summary.lineno}"
408
451
  return None
@@ -413,7 +456,9 @@ class TwistedRuntimeMetrics:
413
456
  if excTraceback is None:
414
457
  return None
415
458
  for summary in reversed(traceback.extract_tb(excTraceback)):
416
- if TwistedRuntimeMetrics._utilSkipInternalMetricsFrame(summary.filename):
459
+ if TwistedRuntimeMetrics._utilSkipInternalMetricsFrame(
460
+ summary.filename
461
+ ):
417
462
  continue
418
463
  return f"{summary.filename}:{summary.name}:{summary.lineno}"
419
464
  return None
@@ -10,11 +10,11 @@ from typing import Any
10
10
  import pytest
11
11
  from twisted.internet.defer import Deferred, fail, succeed
12
12
 
13
- from vortex.VortexUtil import limitConcurrency
14
13
  from vortex.twisted_runtime_metrics import (
15
14
  TwistedRuntimeMetrics,
16
15
  vortexLoopingCallCatchWithMetrics,
17
16
  )
17
+ from vortex.VortexUtil import limitConcurrency
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
 
@@ -46,7 +46,9 @@ def testRecordThreadedCallTracksCountAndLongestMethod() -> None:
46
46
  collector._recordThreadedCall("slow.Method", 100.0)
47
47
  collector._recordThreadedCall("slower.Method", 250.5, "slow.py:run:10")
48
48
  snapshot = TwistedRuntimeMetrics.snapshotAndResetWindow()
49
- assert snapshot.threadedCallCount == 2, "both threaded calls must count in window"
49
+ assert snapshot.threadedCallCount == 2, (
50
+ "both threaded calls must count in window"
51
+ )
50
52
  assert snapshot.longestThreadedMethodName == "slower.Method", (
51
53
  "longest name must be the slowest call"
52
54
  )
@@ -56,18 +58,39 @@ def testRecordThreadedCallTracksCountAndLongestMethod() -> None:
56
58
  assert snapshot.longestThreadedMethodFrame == "slow.py:run:10", (
57
59
  "slow-call frame must be preserved"
58
60
  )
59
- assert snapshot.windowSeconds >= 1, "snapshot must report elapsed window seconds"
61
+ assert snapshot.windowSeconds >= 1, (
62
+ "snapshot must report elapsed window seconds"
63
+ )
64
+
65
+
66
+ def testSnapshotWindowDoesNotResetCounters() -> None:
67
+ TwistedRuntimeMetrics._collector()._recordThreadedCall("one.Method", 50.0)
68
+ firstSnapshot = TwistedRuntimeMetrics.snapshotWindow()
69
+ secondSnapshot = TwistedRuntimeMetrics.snapshotWindow()
70
+ assert firstSnapshot.threadedCallCount == 1, (
71
+ "first snapshot includes recorded call"
72
+ )
73
+ assert secondSnapshot.threadedCallCount == 1, (
74
+ "read-only snapshot must leave window counters intact"
75
+ )
76
+ assert secondSnapshot.longestThreadedMethodMs == 50.0, (
77
+ "read-only snapshot must preserve longest threaded method"
78
+ )
60
79
 
61
80
 
62
81
  def testSnapshotResetsWindowCounters() -> None:
63
82
  TwistedRuntimeMetrics._collector()._recordThreadedCall("one.Method", 50.0)
64
83
  firstSnapshot = TwistedRuntimeMetrics.snapshotAndResetWindow()
65
84
  secondSnapshot = TwistedRuntimeMetrics.snapshotAndResetWindow()
66
- assert firstSnapshot.threadedCallCount == 1, "first snapshot includes recorded call"
85
+ assert firstSnapshot.threadedCallCount == 1, (
86
+ "first snapshot includes recorded call"
87
+ )
67
88
  assert firstSnapshot.longestThreadedMethodMs == 50.0, (
68
89
  "first snapshot longest ms must match recorded call"
69
90
  )
70
- assert secondSnapshot.threadedCallCount == 0, "window counters reset after snapshot"
91
+ assert secondSnapshot.threadedCallCount == 0, (
92
+ "window counters reset after snapshot"
93
+ )
71
94
  assert secondSnapshot.longestThreadedMethodMs == 0.0, (
72
95
  "longest ms resets to zero after snapshot"
73
96
  )
@@ -96,7 +119,9 @@ def testLoopingCallLongestExceptionMethodUsesHighestCount() -> None:
96
119
  collector._recordLoopingCallException("noisyTick", "a.py:2")
97
120
  collector._recordLoopingCallException("quietTick", "b.py:1")
98
121
  snapshot = TwistedRuntimeMetrics.snapshotAndResetWindow()
99
- assert snapshot.loopingCallExceptionCount == 3, "three exceptions must be counted"
122
+ assert snapshot.loopingCallExceptionCount == 3, (
123
+ "three exceptions must be counted"
124
+ )
100
125
  assert snapshot.loopingCallLongestExceptionMethod == "noisyTick", (
101
126
  "longest method is highest per-method exception count"
102
127
  )
@@ -191,9 +216,9 @@ def testLoopingCallCatchWithMetricsRecordsDeferredFailure() -> None:
191
216
  assert snapshot.loopingCallExceptionCount == 1, (
192
217
  "deferred tick failure must increment exception count"
193
218
  )
194
- assert snapshot.loopingCallLongestExceptionMethod == "failingDeferredTick", (
195
- "deferred failure must set longest exception method"
196
- )
219
+ assert (
220
+ snapshot.loopingCallLongestExceptionMethod == "failingDeferredTick"
221
+ ), "deferred failure must set longest exception method"
197
222
  assert snapshot.loopingCallLastExceptionMethod == "failingDeferredTick", (
198
223
  "deferred failure must set last exception method"
199
224
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vortexpy
3
- Version: 4.3.13
3
+ Version: 4.3.14
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
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