Skip to content

Conversation

@dan2k3k4
Copy link
Member

No description provided.

@dan2k3k4 dan2k3k4 force-pushed the add-cleanup-trial-recon-job branch from afeecec to c382ea3 Compare December 23, 2025 19:50
@dan2k3k4 dan2k3k4 requested a review from alagoa December 30, 2025 15:32
Copy link

@alagoa alagoa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review, need to figure out my GH notifications 🤓

Mostly just questions to make sure I understand why we're doing what we are doing here, no major blockers on my side.

Some more doubts (related and unrelated) that came up during review:

  1. This job is not being scheduled in main, is that coming on a later PR?
  2. From what I've seen this does not clash with the other recon jobs we have running, right?
    2a. The main monitor only updates PRODUCT or SYSTEM limits and the trial limits are marked as MANUAL.
    2b. Is the trial team exempt from the soft delete that runs on the main monitor? Even if it isn't explicitly, it probably is in practice, since the team soft delete requires all users of a team to be quiet for >76 days.

users = db.query(DBUser).filter(
DBUser.team_id == trial_team.id,
DBUser.is_active,
DBUser.role == "user"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought (separate PR): could be worth to have an enum for DBUser.role.

Comment on lines +1159 to +1167
for user in users:
# Check budget limit
user_limit = db.query(DBLimitedResource).filter(
and_(
DBLimitedResource.owner_type == OwnerType.USER,
DBLimitedResource.owner_id == user.id,
DBLimitedResource.resource == ResourceType.BUDGET
)
).first()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (optimization): may be worth to make this a single query

Probably not a big impact since we have a small user base, but it's an easy performance optimization, particularly for recon jobs.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like

Suggested change
for user in users:
# Check budget limit
user_limit = db.query(DBLimitedResource).filter(
and_(
DBLimitedResource.owner_type == OwnerType.USER,
DBLimitedResource.owner_id == user.id,
DBLimitedResource.resource == ResourceType.BUDGET
)
).first()
# Fetch all user budget limits in one query
user_limits = db.query(DBLimitedResource).filter(
DBLimitedResource.owner_type == OwnerType.USER,
DBLimitedResource.owner_id.in_([user.id for user in users]),
DBLimitedResource.resource == ResourceType.BUDGET
).all()
user_limit_map = {limit.owner_id: limit for limit in user_limits}

then have the same for loop, getting the limit data from user_limit_map

Comment on lines +1174 to +1190
# 1. Disable user
user.is_active = False
user.updated_at = datetime.now(UTC)

# 2. Disable keys (set duration to 0)
keys = db.query(DBPrivateAIKey).filter(DBPrivateAIKey.owner_id == user.id).all()
for key in keys:
if key.litellm_token and key.region:
try:
litellm_service = LiteLLMService(
api_url=key.region.litellm_api_url,
api_key=key.region.litellm_api_key
)
await litellm_service.update_key_duration(key.litellm_token, "0d")
logger.info(f"Set duration to 0d for key {key.id}")
except Exception as e:
logger.error(f"Failed to expire key {key.id}: {e}")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: this could be put into a soft_delete_user()/deactivate_user() method for reusability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants