-
Notifications
You must be signed in to change notification settings - Fork 2
chore: add recon job to cleanup trial accounts #214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
chore: update various dependencies via dependabot / renovate
afeecec to
c382ea3
Compare
alagoa
left a comment
There was a problem hiding this 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:
- This job is not being scheduled in
main, is that coming on a later PR? - From what I've seen this does not clash with the other recon jobs we have running, right?
2a. The main monitor only updatesPRODUCTorSYSTEMlimits and the trial limits are marked asMANUAL.
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" |
There was a problem hiding this comment.
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.
| 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() |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
something like
| 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
| # 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}") |
There was a problem hiding this comment.
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.
No description provided.