Skip to content

Commit 95cc013

Browse files
authored
Feat: round robin keys (#385)
1 parent e1928a3 commit 95cc013

1 file changed

Lines changed: 35 additions & 6 deletions

File tree

‎src/libkernelbot/launchers/github.py‎

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import io
66
import json
77
import math
8+
import os
89
import pprint
10+
import threading
911
import uuid
1012
import zipfile
1113
import zlib
@@ -58,9 +60,35 @@ class GitHubLauncher(Launcher):
5860
def __init__(self, repo: str, token: str, branch: str):
5961
super().__init__(name="GitHub", gpus=GitHubGPU)
6062
self.repo = repo
61-
self.token = token
63+
self.tokens = self._load_github_tokens(token)
64+
self._token_lock = threading.Lock()
65+
self._token_idx = 0
6266
self.branch = branch
6367

68+
@staticmethod
69+
def _load_github_tokens(fallback_token: str) -> list[str]:
70+
primary = (os.getenv("GITHUB_TOKEN") or fallback_token).strip()
71+
backup = (os.getenv("GITHUB_TOKEN_BACKUP") or "").strip()
72+
73+
tokens: list[str] = []
74+
for t in (primary, backup):
75+
if t and t not in tokens:
76+
tokens.append(t)
77+
78+
if not tokens:
79+
raise KernelBotError(
80+
"No GitHub tokens configured. Set GITHUB_TOKEN "
81+
"(and optionally GITHUB_TOKEN_BACKUP)."
82+
)
83+
84+
return tokens
85+
86+
def _next_token(self) -> str:
87+
with self._token_lock:
88+
token = self.tokens[self._token_idx]
89+
self._token_idx = (self._token_idx + 1) % len(self.tokens)
90+
return token
91+
6492
async def run_submission( # noqa: C901
6593
self, config: dict, gpu_type: GPU, status: RunProgressReporter
6694
) -> FullResult:
@@ -89,7 +117,7 @@ async def run_submission( # noqa: C901
89117
lang_name = {"py": "Python", "cu": "CUDA"}[lang]
90118

91119
logger.info(f"Attempting to trigger GitHub action for {lang_name} on {selected_workflow}")
92-
run = GitHubRun(self.repo, self.token, self.branch, selected_workflow)
120+
run = GitHubRun(self.repo, self._next_token(), self.branch, selected_workflow)
93121
logger.info(f"Successfully created GitHub run: {run.run_id}")
94122

95123
payload = base64.b64encode(zlib.compress(json.dumps(config).encode("utf-8"))).decode(
@@ -176,7 +204,7 @@ class GitHubArtifact:
176204
public_download_url: str
177205

178206

179-
_WORKFLOW_FILE_CACHE: dict[str, Workflow] = {}
207+
_WORKFLOW_FILE_CACHE: dict[tuple[str, str], Workflow] = {}
180208

181209

182210
def patched_create_dispatch(
@@ -248,12 +276,13 @@ def elapsed_time(self):
248276
return datetime.datetime.now(datetime.timezone.utc) - self.start_time
249277

250278
async def get_workflow(self) -> Workflow:
251-
if self.workflow_file in _WORKFLOW_FILE_CACHE:
279+
cache_key = (self.workflow_file, self.token)
280+
if cache_key in _WORKFLOW_FILE_CACHE:
252281
logger.info(f"Returning cached workflow {self.workflow_file}")
253-
return _WORKFLOW_FILE_CACHE[self.workflow_file]
282+
return _WORKFLOW_FILE_CACHE[cache_key]
254283
logger.info(f"Fetching workflow {self.workflow_file} from GitHub")
255284
workflow = self.repo.get_workflow(self.workflow_file)
256-
_WORKFLOW_FILE_CACHE[self.workflow_file] = workflow
285+
_WORKFLOW_FILE_CACHE[cache_key] = workflow
257286
return workflow
258287

259288
async def trigger(self, inputs: dict) -> bool:

0 commit comments

Comments
 (0)