Skip to content

Commit cbb7795

Browse files
committed
v0.3.2.2-beta - [UPDATE] - Big improvements to convergence tracking (more coming soon), implemented "sticky tokens" and "lead callers" for secure data locality and cache isolation. See release_notes.md for further details. ADDED missing critical testing file!!! (Sorry everyone for not noticing the index to my client demo, all demos should be working now.)
1 parent ac39279 commit cbb7795

21 files changed

Lines changed: 1631 additions & 211 deletions

CONTRIBUTING.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ Thanks for your interest in TokenGate.
44

55
---
66

7-
This project is currently shared primarily as a proof of concept.
8-
Feel free to clone, fork, and experiment with the code.
7+
TokenGate is an open-source, open-contribution project.
98

10-
If you'd like to contribute:
9+
Contributions are welcome in the form of bug fixes, new features, documentation improvements, and
10+
any changes that can enhance the usefulness or performance of the system.
1111

12-
- Open an issues when problems arise
13-
- Keep contributions focused and small
14-
- Prefer clarity over cleverness
15-
- Preserve research tone of the project
12+
To contribute to TokenGate please follow these steps:
13+
1. Fork the repository and create a new branch for your changes.
14+
2. Make your changes and ensure that they are well-documented and tested.
15+
3. Submit a pull request with a clear description of your changes and what they solve.
1616

17-
Bug reports, doc clarifications, system modifications, all contributions are welcome.
17+
Please ensure that your code adheres to the existing style and conventions of the project.
18+
19+
Contributions will be reviewed and merged based on their quality, relevance, and alignment with the project's goals.
20+
21+
Thanks for helping to make TokenGate better!

DOCS/BETA.md

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,36 @@
22

33
## Overview
44

5-
Welcome to the TokenGate Beta documentation! This document provides an overview of the current state of the
6-
TokenGate project, including its features, limitations, and future plans. I also include a quick startup guide
7-
for both the WebSocket and regular operations. Please note that this is a beta version, and while it is
8-
stable and actively tested, edge cases and rough spots are expected at this stage.
5+
Welcome to the TokenGate Beta documentation!
96

7+
This document provides an overview of the current state of TokenGate.
108

119
### Current Features
1210

1311
- **Token based concurrency:** The core feature of TokenGate is its token-based concurrency model, which
14-
allows for efficient coordination of tasks across multiple threads.
12+
allows for efficient coordination of tasks across multiple threads.
1513
- **WebSocket support:** TokenGate includes support for WebSocket communication, enabling real-time
1614
monitoring and control of tasks.
17-
- ***DoS protection*:** The token system includes built-in DoS protection ("auto-blocking") to prevent overwhelming
15+
- **DoS protection:** The token system includes built-in DoS protection ("auto-blocking") to prevent overwhelming
1816
the system with too many "failed" concurrent tasks. (Tasks which do not return their result are "failed".)
1917
- **Telemetry:** TokenGate provides telemetry data for tasks, allowing for monitoring and debugging of concurrent
2018
operations with clarity.
19+
- **Flexible API:** The API is designed to be flexible and easy to use, allowing developers to quickly integrate
20+
TokenGate into their applications with minimal setup.
21+
- **Token safety:** The system is designed to prevent data loss and ensure that tokens are properly managed
22+
based on hashing as well as controlled token locality.
2123

2224
### Limitations
2325
- **Beta status:** As a beta project, TokenGate may have bugs or performance issues that have not yet been
2426
identified or resolved.
25-
- **Limited documentation:** The documentation is currently limited and may not cover all aspects of the
26-
project in detail. I plan to expand the documentation as the project progresses.
27+
- **Limited documentation:** The documentation is currently limited and does not cover all aspects of the
28+
project. I plan to expand the documentation as the project progresses.
2729
- **Performance under extreme load:** While TokenGate is designed to handle a high volume of tasks, its
28-
performance under extreme load conditions needs long term analysis.
29-
30-
### Future Plans
31-
- **Improved documentation:** I plan to expand the documentation to provide more detailed information on how
32-
to use TokenGate and its various features.
33-
- **Performance optimizations:** I will continue to optimize the performance of TokenGate, especially under
34-
high load conditions.
35-
- **Additional features:** I am considering adding additional features such as task control mechanisms like
36-
"reset token status" to adjust auto-blocking live and possible dristributed compute support in the future.
30+
performance under extreme load conditions needs long term analysis.
3731

3832
## Get Started
3933

40-
### Detailed startup guide:
41-
42-
#### Using OperationsCoordinator without WebSocket:
34+
### Using OperationsCoordinator event bus *without* WebSocket:
4335
```python
4436
from operations_coordinator import OperationsCoordinator # Must accompany main()
4537
from token_system import task_token_guard # The independent imported decorator for your functions
@@ -68,28 +60,81 @@ def string_operation_task(task_data):
6860
# Setting up an IO-centric method with the token decorator:
6961
# IO writer counts for 'storage_speed':
7062
# 'SLOW' (10 writes), 'MODERATE'(25 writes),
71-
# 'FAST' (50 writes), 'INSANE' (70 writes) <- CAUTION
72-
@task_token_guard(operation_type='data_processing', tags={'weight': 'heavy', 'storage_speed': 'MODERATE'})
63+
# 'FAST' (50 writes), 'INSANE' (70 writes) <- CAUTION only top-end SSDs will handle this.
64+
@task_token_guard(
65+
operation_type='data_processing',
66+
tags={'weight': 'heavy', 'storage_speed': 'MODERATE'}
67+
)
7368
def data_processing_task(task_data):
7469
# Simulate a data processing task
7570
return result
71+
72+
73+
# -----------------------------------NEW*-----------------------------------
74+
# As of v0.2.2.0-beta Awaiting tokens is supported, allowing for more complex
75+
# orchestration patterns. "result = await token" works to await a single token.
76+
77+
# Or a full batch can be awaited with asyncio.gather:
78+
async def main():
79+
coordinator = OperationsCoordinator()
80+
coordinator.start()
81+
try:
82+
tokens = [my_task(i) for i in range(64)]
83+
results = await asyncio.gather(*tokens)
84+
finally:
85+
coordinator.stop()
86+
87+
asyncio.run(main())
88+
89+
# -----------------------------------NEW------------------------------------
90+
# A "sticky_anchor" tag can be added to any decorator to give the sticky
91+
# key an explicit name, independent of operation type. Sticky tokens are
92+
# pinned to the same core domain and create a path for related operations
93+
# to follow the same route, ensuring data locality and consistent performance
94+
# even when the operations do not require this behavior to work.
95+
96+
# This happens automatically when the system interprets tokens with matching
97+
# (operation_type, args) keys.
98+
@task_token_guard(
99+
operation_type="my_op", # Use a unique operation type for clarity.
100+
tags={"weight": "medium", "sticky_anchor": "op_token"},
101+
# The 'sticky_anchor' tag gives this token a specific known moniker.
102+
# Good naming conventions for the sticky_anchor value can assist debugging.
103+
)
104+
def my_operation(n: int) -> int:
105+
...
106+
107+
# -----------------------------------NEW------------------------------------
108+
# "Lead tokens" — those decorated with 'external_calls' generate a SHA-256 seed from their
109+
# token ID and call list. That seed is pinned to a core domain. Any token spawned during
110+
# the lead's execution inherits the seed and gets routed to the same core automatically.
111+
# The domain releases when the lead and all of its children have completed. This is a
112+
# production ready feature that provides deterministic routing, prevents data races,
113+
# and measurably better behaviour under saturated load conditions for complex call chains.
114+
@task_token_guard(
115+
operation_type="lead_op",
116+
tags={"weight": "medium", "external_calls": ["child_op"]},
117+
)
118+
def lead_operation(n: int) -> list:
119+
return [child_op(n + i) for i in range(4)]
76120
```
77121

78-
#### Running the WebSocket server:
122+
### Running the WebSocket server:
123+
79124
```bash
80125
python launch_gui.py OR python -m your_package_root.launch_gui
81126
```
82127
*(Note: Adjust the path if running from outside the repository root).*
83128

84129

85-
#### Using OperationsCoordinator with WebSocket:
130+
#### Using OperationsCoordinator *with* WebSocket:
86131
```python
87132
from operations_coordinator import get_global_coordinator # Must accompany main()
88133

89134
# Get coordinator (GUI already started it)
90135
get_global_coordinator() # One line at module-level to rule the whole WebSocket!
91136

92-
# No specific calls for main using the WebSocket
137+
# No specific calls for main using the WebSocket.
93138
def main():
94139
# Main is free now!
95140
try:
@@ -98,7 +143,7 @@ def main():
98143
pass
99144

100145
if __name__ == "__main__":
101-
main() # This gets used by the entry point in the WebSocket launcher to route 'func' (function)!!!
146+
main() # This gets used by the entry point in the WebSocket launcher to route 'func'!
102147

103148
# Decorated functions will use task_token_guard and the WebSocket integration will
104149
# detect when the coordinated main is running to track task submissions.
@@ -126,8 +171,6 @@ When you first set up your WebSocket environment and want to run a task, you sho
126171
- **Task Launcher:** Your registered task should appear in the task launcher with its description and category.
127172
![Task Launcher](/assets/task_launcher.png)
128173

129-
130-
131174
- **Controls:** When you run the task, there is controls where you can monitor and manage it (e.g., stop, restart).
132175
![Admin Dashboard](/assets/per_operation_controls.png)
133176

@@ -137,8 +180,9 @@ When you first set up your WebSocket environment and want to run a task, you sho
137180

138181
## Conclusion
139182

140-
TokenGate is an active beta project that aims to provide a powerful and flexible concurrency management system
141-
using tokens. While it is currently functional, there are still areas for improvement and optimization. I encourage
142-
users to explore the project, provide feedback, and contribute to its development. 📦 🚀
183+
TokenGate is an active beta project that aims to provide a powerful and flexible production ready
184+
concurrency management system using tokens. While it is currently functional, there are still areas for
185+
improvement and optimization. I encourage users to explore the project, provide feedback, and contribute
186+
to its development. 📦 🚀
143187

144-
To quickly reach out to the developers go here and drop a message (all forms of feedback are accepted): [Tavari](https://www.tavari.online)
188+
To quickly reach out go here and drop a review in the feedback section: [Tavari](https://www.tavari.online)

DOCS/SETUP.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ class OperationsCoordinator: # Under this class are where you find configuration
2424
self,
2525
workers_per_core: int = 4, # Do not modify this without disabling convergence! Do not go under 2 workers.
2626
enable_convergence: bool = True, # Controls dynamic worker counts.
27-
convergence_verbose: bool = False, # Now lives in tg_print!! Controls verbosity, DO NOT enable with REPL.
28-
base_memory_budget_mb: int = 45, # This is a control for operation memory (adjustable).
29-
num_executors: int = 8, # This controls number of parallel executors.
27+
base_memory_budget_mb: int = 45, # This is a control for warming up operation memory locals (adjustable).
28+
num_executors: int = 8, # This controls number of parallel async executers (for token gathering).
3029
auto_block_dangerous: bool = False, # Blocks explosive tasks with possibly dangerous inputs.
3130
):
3231
```

DOCS/proof-of-concept.md

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -673,46 +673,46 @@ def record_task_routed(self, core_id: int, weight: TaskWeight):
673673
self.total_routed += 1
674674
self._affinity_counts[core_id][weight.value] += 1
675675

676-
# Async gathers task tokens setting them to the correct state for execution by workers.
677-
async def _execute_token(self, token: TaskToken, worker_id: str, core_id: int):
678-
"""Execute one admitted token on its already-selected core path.
679-
680-
This method performs the lifecycle transition to EXECUTING, runs the
681-
wrapped callable through the executor-backed path, stores the result or
682-
error on the token, records execution history for the coordinator, and
683-
triggers retry/Guard House hooks when configured.
684-
"""
685-
# Transition to executing
686-
if not token.transition_state(TokenState.EXECUTING):
687-
print(f"[{worker_id.upper()}] Failed to transition {token.token_id}")
688-
return
689-
690-
start_time = time.time()
691-
success = False
676+
# Async gathers task tokens setting them to the correct state for execution with workers.
677+
async def _execute_token(self, token: TaskToken, worker_id: str, core_id: int):
678+
"""Execute one admitted token on its already-selected core path.
679+
680+
This method performs the lifecycle transition to EXECUTING, runs the
681+
wrapped callable through the executor-backed path, stores the result or
682+
error on the token, records execution history for the coordinator, and
683+
triggers retry/Guard House hooks when configured.
684+
"""
685+
# Transition to executing
686+
if not token.transition_state(TokenState.EXECUTING):
687+
print(f"[{worker_id.upper()}] Failed to transition {token.token_id}")
688+
return
692689

693-
try:
694-
loop = asyncio.get_running_loop()
695-
# This is now "partial" instead of lambda for better stability.
696-
bound_func = partial(token.func, *token.args, **token.kwargs)
697-
# We use run_in_executor to execute the task in a thread,
698-
# allowing us to manage concurrency and avoid blocking the event loop.
699-
result = await loop.run_in_executor(None, bound_func)
700-
token.set_result(result)
701-
self.total_executed += 1
702-
success = True
703-
704-
print(f"[{worker_id.upper()}] ✓ Completed {token.token_id}")
690+
start_time = time.time()
691+
success = False
705692

706-
except Exception as e:
707-
# Failed!
708-
token.set_error(e)
709-
self.total_failed += 1
710-
if self.result_verbose:
711-
print(f"[{worker_id.upper()}] ✗ Failed {token.token_id}: {e}")
712-
713-
finally:
714-
execution_duration = time.time() - start_time
715-
# Additional execution recording and Guard House checks would go below here.
693+
try:
694+
loop = asyncio.get_running_loop()
695+
# This is now "partial" instead of lambda for better stability.
696+
bound_func = partial(token.func, *token.args, **token.kwargs)
697+
# We use run_in_executor to execute the task in a thread,
698+
# allowing us to manage concurrency and avoid blocking the event loop.
699+
result = await loop.run_in_executor(None, bound_func)
700+
token.set_result(result)
701+
self.total_executed += 1
702+
success = True
703+
704+
print(f"[{worker_id.upper()}] ✓ Completed {token.token_id}")
705+
706+
except Exception as e:
707+
# Failed!
708+
token.set_error(e)
709+
self.total_failed += 1
710+
if self.result_verbose:
711+
print(f"[{worker_id.upper()}] ✗ Failed {token.token_id}: {e}")
712+
713+
finally:
714+
execution_duration = time.time() - start_time
715+
# Additional execution recording and Guard House checks would go below here.
716716
```
717717

718718
### Mailboxes:

0 commit comments

Comments
 (0)