Skip to content

Commit c8e8f7f

Browse files
committed
fix: refactor user-repos and archived endpoints to use service methods
- Changed list_user_repositories to call service.list_user_repos() instead of direct store access - Changed list_archived_repositories to call service.list_archived_repos() instead of direct store access - Removes duplicate executor wrapping (already handled in service layer) - Ensures proper session management through service methods - Should fix hanging issues on these endpoints
1 parent 2726254 commit c8e8f7f

File tree

4 files changed

+37
-53
lines changed

4 files changed

+37
-53
lines changed

commitly-backend/app/api/github.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ async def github_status(
5858
session: Session = Depends(get_db),
5959
):
6060
import asyncio
61-
61+
6262
# Wrap sync DB call in executor to avoid blocking event loop
6363
def get_status():
6464
store = GitHubTokenStore(session)
6565
return store.get_token(current_user["sub"])
66-
66+
6767
loop = asyncio.get_event_loop()
6868
record = await loop.run_in_executor(None, get_status)
69-
69+
7070
if record is None:
7171
return OAuthStatusResponse(connected=False)
7272
return OAuthStatusResponse(

commitly-backend/app/api/roadmap.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,8 @@ async def list_user_repositories(
214214
current_user: ClerkClaims = Depends(require_clerk_auth),
215215
service: RoadmapService = Depends(get_roadmap_service),
216216
) -> list[UserRepoStateResponse]:
217-
import asyncio
218-
219-
# Wrap sync DB call in executor to avoid blocking event loop
220217
user_id = get_user_id(current_user)
221-
222-
def get_repos():
223-
return service._pin_store.list_states(user_id)
224-
225-
loop = asyncio.get_event_loop()
226-
return await loop.run_in_executor(None, get_repos)
218+
return await service.list_user_repos(user_id)
227219

228220

229221
@router.post("/sync/{owner}/{repo}", response_model=UserRepoStateResponse)
@@ -272,16 +264,8 @@ async def list_archived_repositories(
272264
current_user: ClerkClaims = Depends(require_clerk_auth),
273265
service: RoadmapService = Depends(get_roadmap_service),
274266
) -> list[UserRepoStateResponse]:
275-
import asyncio
276-
277-
# Wrap sync DB call in executor to avoid blocking event loop
278267
user_id = get_user_id(current_user)
279-
280-
def get_archived():
281-
return service._pin_store.list_archived(user_id)
282-
283-
loop = asyncio.get_event_loop()
284-
return await loop.run_in_executor(None, get_archived)
268+
return await service.list_archived_repos(user_id)
285269

286270

287271
@router.post("/{owner}/{repo}/rating", response_model=RatingResponse)

commitly-backend/app/core/auth.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ async def verify_clerk_token_async(token: str) -> ClerkClaims:
222222
"""Async version of verify_clerk_token that doesn't block the event loop."""
223223
import asyncio
224224
import logging
225-
225+
226226
logger = logging.getLogger(__name__)
227227
logger.info("verify_clerk_token_async: Starting token verification")
228228

@@ -237,7 +237,7 @@ async def verify_clerk_token_async(token: str) -> ClerkClaims:
237237
if not isinstance(kid, str):
238238
logger.error("verify_clerk_token_async: Missing key identifier")
239239
raise InvalidClerkToken("Missing key identifier")
240-
240+
241241
logger.info(f"verify_clerk_token_async: Fetching JWKS for kid={kid}")
242242

243243
# Use async version to avoid blocking
@@ -262,7 +262,7 @@ def verify_signature():
262262
if not public_key.verify(message.encode("utf-8"), decoded_signature):
263263
logger.error("verify_signature: Signature verification failed")
264264
raise InvalidClerkToken("Signature verification failed")
265-
265+
266266
logger.info("verify_signature: Signature verified, getting claims")
267267
claims = jwt.get_unverified_claims(token)
268268
logger.info("verify_signature: Claims retrieved")

commitly-backend/app/services/roadmap_service.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ async def record_roadmap_view(
205205
user_id: User identifier (optional for anonymous users)
206206
"""
207207
import asyncio
208-
208+
209209
if not self._view_tracker:
210210
# View tracking disabled
211211
return
@@ -220,7 +220,7 @@ def record_view():
220220
if should_count:
221221
# Increment the view count on the roadmap
222222
self._result_store.increment_view_count(repo_full_name)
223-
223+
224224
loop = asyncio.get_event_loop()
225225
await loop.run_in_executor(None, record_view)
226226

@@ -238,52 +238,52 @@ async def sync_repo(
238238
self, owner: str, repo: str, user_id: str
239239
) -> UserRepoStateResponse:
240240
import asyncio
241-
241+
242242
full_name = f"{owner}/{repo}"
243-
243+
244244
# Wrap DB operations in executor
245245
loop = asyncio.get_event_loop()
246-
246+
247247
def get_roadmap():
248248
return self._result_store.get(full_name)
249-
249+
250250
roadmap = await loop.run_in_executor(None, get_roadmap)
251-
251+
252252
if roadmap is None:
253253
await self.generate(
254254
repo_url=f"https://github.com/{full_name}",
255255
force_refresh=False,
256256
actor_id=user_id,
257257
)
258258
roadmap = await loop.run_in_executor(None, get_roadmap)
259-
259+
260260
if roadmap is None:
261261
raise HTTPException(
262262
status_code=status.HTTP_404_NOT_FOUND,
263263
detail="Roadmap could not be generated for this repository.",
264264
)
265-
265+
266266
def check_and_upsert():
267267
states = self._pin_store.list_states(user_id)
268268
was_synced = any(state.repo_full_name == full_name for state in states)
269-
269+
270270
self._pin_store.upsert_state(
271271
user_id,
272272
full_name,
273273
status="synced",
274274
is_archived=False,
275275
progress_percent=0,
276276
)
277-
277+
278278
record_after = self._result_store.get(full_name)
279279
if not was_synced:
280280
self._result_store.increment_sync_count(full_name)
281281
record_after = self._result_store.get(full_name)
282-
282+
283283
return was_synced, record_after
284-
284+
285285
was_synced, record_after = await loop.run_in_executor(None, check_and_upsert)
286-
286+
287287
return UserRepoStateResponse(
288288
repo_full_name=full_name,
289289
status="synced",
@@ -295,16 +295,16 @@ def check_and_upsert():
295295

296296
async def desync_repo(self, owner: str, repo: str, user_id: str) -> None:
297297
import asyncio
298-
298+
299299
full_name = f"{owner}/{repo}"
300-
300+
301301
def desync():
302302
states = self._pin_store.list_states(user_id)
303303
had_state = any(state.repo_full_name == full_name for state in states)
304304
self._pin_store.unpin(user_id, full_name)
305305
if had_state:
306306
self._result_store.decrement_sync_count(full_name)
307-
307+
308308
loop = asyncio.get_event_loop()
309309
await loop.run_in_executor(None, desync)
310310

@@ -318,9 +318,9 @@ async def archive_repo(
318318
) -> UserRepoStateResponse:
319319
"""Archive a repository for a user."""
320320
import asyncio
321-
321+
322322
full_name = f"{owner}/{repo}"
323-
323+
324324
def archive():
325325
states = self._pin_store.list_states(user_id)
326326
existing_state = next(
@@ -343,7 +343,7 @@ def archive():
343343
detail="Failed to archive repository.",
344344
)
345345
return updated_state
346-
346+
347347
loop = asyncio.get_event_loop()
348348
return await loop.run_in_executor(None, archive)
349349

@@ -352,9 +352,9 @@ async def unarchive_repo(
352352
) -> UserRepoStateResponse:
353353
"""Unarchive a repository for a user."""
354354
import asyncio
355-
355+
356356
full_name = f"{owner}/{repo}"
357-
357+
358358
def unarchive():
359359
archived = self._pin_store.list_archived(user_id)
360360
existing_archived = next(
@@ -377,7 +377,7 @@ def unarchive():
377377
detail="Failed to unarchive repository.",
378378
)
379379
return updated_state
380-
380+
381381
loop = asyncio.get_event_loop()
382382
return await loop.run_in_executor(None, unarchive)
383383

@@ -392,14 +392,14 @@ async def set_rating(
392392
) -> RatingResponse:
393393
"""Set or update a user's rating for a repository."""
394394
import asyncio
395-
395+
396396
if not self._rating_store:
397397
raise HTTPException(
398398
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
399399
detail="Rating service is not available",
400400
)
401401
full_name = f"{owner}/{repo}"
402-
402+
403403
def upsert():
404404
record = self._rating_store.upsert_rating(user_id, full_name, rating)
405405
return RatingResponse(
@@ -409,7 +409,7 @@ def upsert():
409409
created_at=record.created_at,
410410
updated_at=record.updated_at,
411411
)
412-
412+
413413
loop = asyncio.get_event_loop()
414414
return await loop.run_in_executor(None, upsert)
415415

@@ -418,11 +418,11 @@ async def get_user_rating(
418418
) -> RatingResponse | None:
419419
"""Get a user's rating for a repository."""
420420
import asyncio
421-
421+
422422
if not self._rating_store:
423423
return None
424424
full_name = f"{owner}/{repo}"
425-
425+
426426
def get_rating():
427427
record = self._rating_store.get_user_rating(user_id, full_name)
428428
if not record:
@@ -434,7 +434,7 @@ def get_rating():
434434
created_at=record.created_at,
435435
updated_at=record.updated_at,
436436
)
437-
437+
438438
loop = asyncio.get_event_loop()
439439
return await loop.run_in_executor(None, get_rating)
440440
return RatingResponse(

0 commit comments

Comments
 (0)