abstract-block-dumper 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl

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.
@@ -1,8 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
1
5
  import bittensor as bt
2
6
  import structlog
3
7
 
4
8
  import abstract_block_dumper._internal.services.utils as abd_utils
5
9
 
10
+ if TYPE_CHECKING:
11
+ import types
12
+
6
13
  logger = structlog.get_logger(__name__)
7
14
 
8
15
 
@@ -13,6 +20,10 @@ ARCHIVE_BLOCK_THRESHOLD = 300
13
20
  class BittensorConnectionClient:
14
21
  """
15
22
  Manages connections to regular and archive Bittensor subtensor networks.
23
+
24
+ Supports context manager protocol for safe connection cleanup:
25
+ with BittensorConnectionClient(network="finney") as client:
26
+ block = client.subtensor.get_current_block()
16
27
  """
17
28
 
18
29
  def __init__(self, network: str) -> None:
@@ -21,6 +32,38 @@ class BittensorConnectionClient:
21
32
  self._archive_subtensor: bt.Subtensor | None = None
22
33
  self._current_block_cache: int | None = None
23
34
 
35
+ def __enter__(self) -> BittensorConnectionClient:
36
+ """Context manager entry."""
37
+ return self
38
+
39
+ def __exit__(
40
+ self,
41
+ _exc_type: type[BaseException] | None,
42
+ _exc_val: BaseException | None,
43
+ _exc_tb: types.TracebackType | None,
44
+ ) -> None:
45
+ """Context manager exit - ensures connections are closed."""
46
+ self.close()
47
+
48
+ def close(self) -> None:
49
+ """Close all subtensor connections to prevent memory leaks."""
50
+ if self._subtensor is not None:
51
+ try:
52
+ self._subtensor.close()
53
+ except Exception:
54
+ logger.warning("Error closing subtensor connection", exc_info=True)
55
+ self._subtensor = None
56
+
57
+ if self._archive_subtensor is not None:
58
+ try:
59
+ self._archive_subtensor.close()
60
+ except Exception:
61
+ logger.warning("Error closing archive subtensor connection", exc_info=True)
62
+ self._archive_subtensor = None
63
+
64
+ self._current_block_cache = None
65
+ logger.debug("Subtensor connections closed")
66
+
24
67
  def get_for_block(self, block_number: int) -> bt.Subtensor:
25
68
  """Get the appropriate subtensor client for the given block number."""
26
69
  raise NotImplementedError
@@ -71,8 +114,6 @@ class BittensorConnectionClient:
71
114
  return self.subtensor
72
115
 
73
116
  def refresh_connections(self) -> None:
74
- """Reset all subtensor connections to force re-establishment."""
75
- self._subtensor = None
76
- self._archive_subtensor = None
77
- self._current_block_cache = None
78
- logger.info("Subtensor connections reset")
117
+ """Close and reset all subtensor connections to force re-establishment."""
118
+ self.close()
119
+ logger.info("Subtensor connections refreshed")
@@ -36,8 +36,6 @@ logger = structlog.get_logger(__name__)
36
36
  # Blocks older than this threshold from current head require archive network
37
37
  ARCHIVE_BLOCK_THRESHOLD = 300
38
38
 
39
- # Progress logging interval
40
- PROGRESS_LOG_INTERVAL = 100
41
39
  ARCHIVE_NETWORK = "archive"
42
40
 
43
41
  # Memory cleanup interval (every N blocks)
@@ -281,16 +279,13 @@ class BackfillScheduler:
281
279
  if self._current_head_cache:
282
280
  set_block_lag("backfill", self._current_head_cache - block_number)
283
281
 
284
- # Log progress periodically
285
- if processed_count % PROGRESS_LOG_INTERVAL == 0:
286
- progress_pct = (processed_count / total_blocks) * 100
287
- logger.info(
288
- "Backfill progress",
289
- processed=processed_count,
290
- total=total_blocks,
291
- progress_percent=f"{progress_pct:.1f}%",
292
- current_block=block_number,
293
- )
282
+ # Log each block being processed
283
+ progress_pct = (processed_count / total_blocks) * 100
284
+ logger.info(
285
+ "Backfilling block",
286
+ block=block_number,
287
+ progress=f"{processed_count}/{total_blocks} ({progress_pct:.1f}%)",
288
+ )
294
289
 
295
290
  # Rate limiting between block submissions
296
291
  if block_number < self.to_block and self.rate_limit > 0:
@@ -2,7 +2,6 @@ import time
2
2
  from typing import Protocol
3
3
 
4
4
  import structlog
5
- from django import db
6
5
  from django.conf import settings
7
6
 
8
7
  import abstract_block_dumper._internal.dal.django_dal as abd_dal
@@ -16,9 +15,6 @@ from abstract_block_dumper._internal.services.metrics import (
16
15
  set_registered_tasks,
17
16
  )
18
17
 
19
- # Refresh bittensor connections every N blocks to prevent memory leaks from internal caches
20
- CONNECTION_REFRESH_INTERVAL = 1000
21
-
22
18
  logger = structlog.get_logger(__name__)
23
19
 
24
20
 
@@ -42,6 +38,7 @@ class DefaultBlockStateResolver:
42
38
  return self.bittensor_client.subtensor.get_current_block()
43
39
  if isinstance(start_setting, int):
44
40
  return start_setting
41
+
45
42
  # Default: resume from DB or current
46
43
  return abd_dal.get_the_latest_executed_block_number() or self.bittensor_client.subtensor.get_current_block()
47
44
 
@@ -59,7 +56,6 @@ class TaskScheduler:
59
56
  self.bittensor_client = bittensor_client
60
57
  self.last_processed_block = state_resolver.get_starting_block()
61
58
  self.is_running = False
62
- self._blocks_since_refresh = 0
63
59
 
64
60
  def start(self) -> None:
65
61
  self.is_running = True
@@ -86,11 +82,6 @@ class TaskScheduler:
86
82
  increment_blocks_processed("realtime")
87
83
  set_block_lag("realtime", 0) # Head-only mode has no lag
88
84
  self.last_processed_block = current_block
89
- self._blocks_since_refresh += 1
90
-
91
- # Periodic memory cleanup
92
- if self._blocks_since_refresh >= CONNECTION_REFRESH_INTERVAL:
93
- self._perform_cleanup()
94
85
 
95
86
  time.sleep(self.poll_interval)
96
87
 
@@ -104,19 +95,9 @@ class TaskScheduler:
104
95
 
105
96
  def stop(self) -> None:
106
97
  self.is_running = False
98
+ self.bittensor_client.close()
107
99
  logger.info("TaskScheduler stopped.")
108
100
 
109
- def _perform_cleanup(self) -> None:
110
- """Perform periodic memory cleanup to prevent leaks in long-running processes."""
111
- # Reset bittensor connections to clear internal caches
112
- self.bittensor_client.refresh_connections()
113
-
114
- # Clear Django's query log (only accumulates if DEBUG=True)
115
- db.reset_queries()
116
-
117
- self._blocks_since_refresh = 0
118
- logger.debug("Memory cleanup performed", blocks_processed=CONNECTION_REFRESH_INTERVAL)
119
-
120
101
 
121
102
  def task_scheduler_factory(network: str = "finney") -> TaskScheduler:
122
103
  """
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.1.1'
32
- __version_tuple__ = version_tuple = (0, 1, 1)
31
+ __version__ = version = '0.1.2'
32
+ __version_tuple__ = version_tuple = (0, 1, 2)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: abstract-block-dumper
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Project-URL: Source, https://github.com/bactensor/abstract-block-dumper
5
5
  Project-URL: Issue Tracker, https://github.com/bactensor/abstract-block-dumper/issues
6
6
  Author-email: Reef Technologies <opensource@reef.pl>
@@ -1,5 +1,5 @@
1
1
  abstract_block_dumper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- abstract_block_dumper/_version.py,sha256=m8HxkqoKGw_wAJtc4ZokpJKNLXqp4zwnNhbnfDtro7w,704
2
+ abstract_block_dumper/_version.py,sha256=Ok5oAXdWgR9aghaFXTafTeDW6sYO3uVe6d2Nket57R4,704
3
3
  abstract_block_dumper/admin.py,sha256=3J3I_QOKFgfMNpTXW-rTQGO_q5Ls6uNuL0FkPVdIsYg,1654
4
4
  abstract_block_dumper/apps.py,sha256=DXATdrjsL3T2IletTbKeD6unr8ScLaxg7wz0nAHTAns,215
5
5
  abstract_block_dumper/models.py,sha256=MO9824dmHB6xF3PrFE_RERh7whVjQtS4tt6QA0wSbg0,2022
@@ -11,13 +11,13 @@ abstract_block_dumper/_internal/dal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
11
11
  abstract_block_dumper/_internal/dal/django_dal.py,sha256=QbDsikUthIAhVC_FwSynUUdQL3OWlCo3_Cg65M91Cb4,5618
12
12
  abstract_block_dumper/_internal/dal/memory_registry.py,sha256=m9Yms-cuemi9_5q_Kn_zsJnxDPEiuAUkESIAltD60QY,2943
13
13
  abstract_block_dumper/_internal/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- abstract_block_dumper/_internal/providers/bittensor_client.py,sha256=hkUdkhz8wOZInRloyySo3DDN4JSMEiPwLv0YV5IDZ7o,2798
14
+ abstract_block_dumper/_internal/providers/bittensor_client.py,sha256=wlKjFrGN4Q2DfQyD_Fx-eH83ZMB6AbzLs5keYq6FGUw,4124
15
15
  abstract_block_dumper/_internal/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- abstract_block_dumper/_internal/services/backfill_scheduler.py,sha256=uZqM4bSoMgNRKwBy-W3a7ydh2Z37Sum8cDRGo4T4KhA,16319
16
+ abstract_block_dumper/_internal/services/backfill_scheduler.py,sha256=3X9NRXCamnb1jUI47sUXqmsrQ1nBzK0BLKe5CeLt00E,16091
17
17
  abstract_block_dumper/_internal/services/block_processor.py,sha256=P8_LZR4ZSyNKbtnqFbAUkpT1XmEh9yX5Pgj5J__IwdA,7409
18
18
  abstract_block_dumper/_internal/services/executor.py,sha256=WhpHhOAi4cI-qdEE8-DSt9xZwooOpSc9_uDMQBBoHUM,2317
19
19
  abstract_block_dumper/_internal/services/metrics.py,sha256=Gg-PQYZ98caaS52wm1EqhtPURXlfrVjk2t3-8nccqfo,7821
20
- abstract_block_dumper/_internal/services/scheduler.py,sha256=pkcOlh0XsR-3sStEtTbiSpHFJhMG9tGIgSUFeH-FITk,5020
20
+ abstract_block_dumper/_internal/services/scheduler.py,sha256=BIQ7c-HYSebW3CKq5ynsMZjULEO9c5YP0qWFN1aqg24,4164
21
21
  abstract_block_dumper/_internal/services/utils.py,sha256=QZxdQyWIcUnezyVmegS4g3x3BoB3-oijYJ_i9nLQWHo,1140
22
22
  abstract_block_dumper/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  abstract_block_dumper/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -29,6 +29,6 @@ abstract_block_dumper/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
29
29
  abstract_block_dumper/v1/celery.py,sha256=X4IqVs5i6ZpyY7fy1SqMZgsZy4SXP-jK2qG-FYnjU38,1722
30
30
  abstract_block_dumper/v1/decorators.py,sha256=yQglsy1dU1u7ShwaTqZLahDcybHmetibTIOi53o_ZOM,9829
31
31
  abstract_block_dumper/v1/tasks.py,sha256=u9iMYdDUqzYT3yPrNwZecHnlweZ3yFipV9BcIWHCbus,2647
32
- abstract_block_dumper-0.1.1.dist-info/METADATA,sha256=CVrs2LOv57Y4JOGxJgKsr1Xnnhl0i0wa534T-0hTU58,12993
33
- abstract_block_dumper-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
34
- abstract_block_dumper-0.1.1.dist-info/RECORD,,
32
+ abstract_block_dumper-0.1.2.dist-info/METADATA,sha256=6y5tq_8Wp3JNHuYATBIx_XQ2I0mXqBU5tgyf97rHahc,12993
33
+ abstract_block_dumper-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
34
+ abstract_block_dumper-0.1.2.dist-info/RECORD,,