Tenant-Centric Quota Management with Manual Overrides
Managing resource quotas across multiple tenants can be challenging, especially when the need for manual overrides arises. This post explores how we refactored our token usage service to implement a tenant-centric quota system with support for manual adjustments.
The Challenge
Previously, our token quota management was user-based. This created inefficiencies when the context already provided the tenant information. We needed a more direct way to manage quotas at the tenant level, allowing for specific overrides when necessary.
The Solution: Tenant-Centric Design
We shifted the focus from individual users to tenants. This involved the following key changes:
- Plan Resolution: Moved plan resolution logic to a
Tenant::resolvePlan()method. This centralizes the process of determining a tenant's plan based on various factors. - Effective Daily Token Limit: Introduced a
Tenant::getEffectiveDailyTokenLimit()method. This method calculates the daily token limit for a tenant, taking into account the plan and any manual overrides. - Manual Override: Added a
daily_token_limitcolumn to the tenant configuration. This allows administrators to set a specific token limit for a tenant, overriding the default limit from the plan. - Quota Method Updates: Modified all quota-related methods (
canGenerate,getEffectiveLimit,getRemainingTokens,isNearLimit) to accept aTenantobject instead of aUserobject. This simplifies the calling code by removing the need to resolve users when the tenant is already available.
Implementing Manual Overrides
The core of the solution lies in the Tenant::getEffectiveDailyTokenLimit() method. Here's a simplified example of how it might work:
class Tenant
{
public function resolvePlan(): Plan
{
// Logic to determine the tenant's plan based on subscription, usage, etc.
return new BasicPlan();
}
public function getEffectiveDailyTokenLimit(): int
{
if ($this->daily_token_limit !== null) {
return $this->daily_token_limit; // Manual override
}
return $this->resolvePlan()->getDailyTokenLimit(); // Default from plan
}
}
class Plan {
public function getDailyTokenLimit(): int {
return 1000; // Basic Plan limit
}
}
class BasicPlan extends Plan {
}
This code snippet demonstrates how the method checks for a manual override ($this->daily_token_limit) and, if present, returns that value. Otherwise, it retrieves the default token limit from the tenant's plan.
Benefits
- Simplified Code: Eliminates the need to resolve users when the tenant context is already known.
- Centralized Logic: Consolidates plan resolution and token limit calculation in the
Tenantmodel. - Flexibility: Provides a mechanism for manual overrides, allowing administrators to adjust quotas as needed.
Conclusion
By refactoring our token usage service to be tenant-centric and incorporating manual overrides, we've created a more efficient and flexible system for managing resource quotas. Key takeaways include:
- Prioritize tenant-level operations when the tenant context is readily available.
- Centralize plan resolution and limit calculation for better maintainability.
- Implement manual overrides to handle exceptions and specific tenant needs.