Quotas¶
Objectif¶
Le mécanisme de quotas sert à suivre et éventuellement limiter certaines consommations d'une instance FMT.
Il couvre par exemple :
- le nombre de lots principaux ;
- le nombre de garages ou parkings ;
- le nombre de documents stockés dans l'EDMS ;
- le volume de stockage EDMS ;
- le nombre d'utilisateurs actifs ;
- le nombre d'appels Google Document AI ;
- le nombre d'e-mails envoyés ;
- la taille de la base de données.
Pour les PO, un quota répond à deux questions :
- quelle consommation veut-on suivre ?
- à partir de quelle limite faut-il alerter ou bloquer ?
Pour les DEV, le quota est une couche d'orchestration entre :
- une définition de métrique (
infra\metering\MetricDefinition) ; - un quota opérationnel (
infra\quota\Quota) ; - un ou plusieurs seuils (
infra\quota\QuotaThreshold) ; - des collecteurs de valeur (
infra_metering_*) ; - des contrôleurs de disponibilité (
infra_quota_check-*) ; - des actions déclenchées lorsque des seuils sont atteints (
infra_quota_handle-*).
Vue d'ensemble¶
Le système distingue deux moments de contrôle.
1. Vérification avant une opération¶
Avant certaines créations ou opérations sensibles, le code appelle :
Quota::search([['code', '=', '<quota_code>']])
->do('check-availability', $values);
Cette vérification est utilisée comme garde-fou applicatif. Elle doit rester légère, car elle est exécutée dans des chemins critiques comme la création d'un document, d'un utilisateur ou d'un lot.
Elle ne doit pas recalculer toute la consommation réelle. Elle travaille principalement avec la valeur stockée du quota et les informations du candidat en cours de création.
2. Recalcul périodique de l'état réel¶
La tâche infra_quota_refresh-values rafraîchit les valeurs des quotas actifs via les collecteurs, puis vérifie les seuils.
Ce recalcul est plus coûteux, mais il est exécuté en tâche de fond ou via un flux d'administration. Il sert à maintenir l'état global cohérent avec les données réelles de l'instance.
Modèle fonctionnel¶
MetricDefinition¶
Une MetricDefinition décrit ce qui est mesuré.
Champs principaux :
| Champ | Rôle |
|---|---|
code |
Code stable de la métrique, par exemple edms.storage.size. |
name |
Libellé métier de la métrique. |
unit |
Unité de mesure : count, bytes, calls. |
collector |
Contrôleur get capable de calculer la valeur réelle. |
is_active |
Indique si la métrique est active. |
Le collecteur doit retourner une structure contenant au minimum :
[
'value' => <integer>
]
Quota¶
Un Quota applique une logique de suivi ou de blocage à une métrique.
Champs principaux :
| Champ | Rôle |
|---|---|
metric_definition_id |
Métrique suivie par le quota. |
code |
Code calculé depuis la métrique. |
quota_type |
instant ou period. |
period_duration |
Durée de période : day, week, month, year. |
period_start / period_end |
Bornes de période pour les quotas périodiques. |
value |
Dernière valeur connue du quota. |
is_reached |
Etat agrégé : au moins un seuil bloquant est atteint. |
is_active |
Si faux, le quota est ignoré par les contrôles. |
availability_controller |
Contrôleur spécialisé pour vérifier un candidat. |
thresholds_ids |
Seuils associés au quota. |
is_reached est volontairement agrégé. Il ne dit pas quel seuil précis a été atteint. Il indique seulement que le quota est actuellement dans un état bloquant.
QuotaThreshold¶
Un QuotaThreshold décrit une limite à partir de laquelle une action peut être exécutée et/ou le quota peut devenir bloquant.
Champs principaux :
| Champ | Rôle |
|---|---|
quota_id |
Quota concerné. |
threshold_type |
blocking ou non_blocking. |
value |
Valeur minimale à atteindre. |
max_value |
Valeur maximale optionnelle pour limiter la plage de déclenchement. |
action |
Contrôleur do à appeler lorsque le seuil se déclenche. |
trigger_policy |
Politique de déclenchement de l'action : on_reach ou always. |
threshold_type = blocking influence Quota.is_reached.
threshold_type = non_blocking permet de déclencher une action sans bloquer directement la fonctionnalité.
Types de quota¶
Quota instantané¶
Un quota instant mesure l'état courant de l'instance.
Exemples :
- nombre de documents EDMS ;
- volume de stockage EDMS ;
- nombre d'utilisateurs ;
- nombre de lots principaux ;
- taille de la base de données.
La valeur représente l'état actuel observé au dernier refresh.
Quota périodique¶
Un quota period mesure une consommation cumulée sur une période.
Exemples :
- appels Google Document AI sur la semaine ;
- e-mails envoyés sur la semaine.
Les champs period_start et period_end définissent la fenêtre utilisée par le collecteur.
L'action infra_quota_shift-periods décale les périodes expirées vers la période courante et remet is_reached à false. Cela permet à un quota périodique de redevenir consommable au début d'une nouvelle période.
Contrôle de disponibilité¶
Rôle¶
check-availability répond à la question :
L'opération candidate est-elle autorisée compte tenu de l'état actuel du quota ?
Il est utilisé dans des méthodes comme cancreate() avant de créer un objet.
Exemples de consommateurs :
- création d'un
documents\Document; - création d'un
identity\User; - création d'un
realestate\property\PropertyLot; - exécution du spool d'e-mails.
Logique générale¶
Pour chaque quota ciblé :
- si
is_active = false, le quota est ignoré ; - si aucun
availability_controllern'est configuré : is_reached = truebloque l'opération ;- sinon l'opération est autorisée par ce quota ;
- si un
availability_controllerest configuré : - le contrôleur spécialisé reçoit le code du quota, le delta et les valeurs candidates ;
- s'il retourne
allowed = false, l'opération est bloquée.
Cette approche évite d'appeler systématiquement les collecteurs complets. Le contrôle avant opération reste donc rapide.
Contrôleurs spécialisés¶
Les contrôleurs spécialisés sont des providers get placés dans packages/infra/data/quota.
Ils servent à gérer les cas où tous les candidats ne consomment pas réellement le quota.
Exemples :
- un utilisateur système ne doit pas compter dans
auth.users.count; - un lot secondaire ne doit pas compter dans
property.main_lots.count; - un lot qui n'est pas garage/parking ne doit pas compter dans
property.parkings.count; - un document EDMS consomme à la fois un compteur de documents et un volume de stockage.
Contrat attendu :
[
'allowed' => true|false,
'reason' => null|'quota_unavailable',
'code' => '<quota_code>',
'value' => <current_value>,
'delta' => <candidate_delta>,
'projected_value' => <value + delta>,
'threshold_id' => null|<id>
]
Le provider doit rester léger. Il ne doit pas recalculer toute la métrique via le collecteur ; il se base sur la valeur stockée du quota et sur les valeurs candidates.
Rafraîchissement des valeurs¶
Action refresh-value¶
L'action ORM refresh-value est portée par Quota.
Elle :
- lit la métrique associée ;
- appelle le collecteur configuré dans
MetricDefinition.collector; - transmet
period_startetperiod_endpour les quotas périodiques ; - met à jour
Quota.valueavec la valeur retournée.
Action check-thresholds¶
Après rafraîchissement, check-thresholds évalue les seuils du quota.
Pour chaque seuil :
- le seuil est considéré comme atteint si
Quota.value >= QuotaThreshold.value; - l'action du seuil n'est possible que si
max_valueest vide ou siQuota.value <= max_value; - si le seuil est
blocking, le quota devientis_reached = true; - si les conditions de déclenchement sont remplies, le contrôleur
QuotaThreshold.actionest appelé.
L'état Quota.is_reached est ensuite synchronisé avec le résultat global des seuils bloquants.
Politique de déclenchement des actions¶
Le champ QuotaThreshold.trigger_policy contrôle quand l'action du seuil est exécutée.
on_reach¶
Politique par défaut.
L'action est déclenchée uniquement si le quota n'était pas déjà is_reached avant le check.
Cette politique évite de rejouer une action à chaque tâche de refresh lorsque le quota reste au-dessus de la limite.
Elle convient pour :
- des notifications ;
- des alertes de dépassement ;
- des opérations qui ne doivent pas être répétées inutilement.
Limite connue : is_reached est agrégé au niveau du quota. Si plusieurs seuils existent sur le même quota, on_reach ne distingue pas quel seuil précis a déjà été franchi.
always¶
L'action est déclenchée à chaque check-thresholds tant que le seuil correspond.
Cette politique convient uniquement aux actions idempotentes ou volontairement répétables.
Exemples :
- resynchroniser un état technique ;
- recréer une alerte si le système en dépend ;
- exécuter une vérification périodique non destructive.
Actions de seuil¶
Les actions de seuil sont des contrôleurs do, par exemple :
infra_quota_handle-property-main-lots-count-reachedinfra_quota_handle-property-parkings-count-reachedinfra_quota_handle-edms-document-count-reachedinfra_quota_handle-edms-storage-size-reachedinfra_quota_handle-google-docai-calls-count-reachedinfra_quota_handle-instance-users-count-reachedinfra_quota_handle-mail-outbound-count-reachedinfra_quota_handle-db-storage-size-reached
Elles sont prévues pour centraliser les effets liés à un dépassement : notification, log, alerte, mise à jour d'état ou action administrative.
Par convention, elles doivent être idempotentes si le seuil utilise trigger_policy = always.
Quotas configurés¶
| Code | Type | Collecteur | Disponibilité spécialisée | Action de seuil |
|---|---|---|---|---|
property.main_lots.count |
instant |
infra_metering_read-property-main-lots-count |
infra_quota_check-property-main-lots-count-availability |
infra_quota_handle-property-main-lots-count-reached |
property.parkings.count |
instant |
infra_metering_read-property-parkings-count |
infra_quota_check-property-parkings-count-availability |
infra_quota_handle-property-parkings-count-reached |
edms.document.count |
instant |
infra_metering_read-edms-document-count |
infra_quota_check-edms-document-count-availability |
infra_quota_handle-edms-document-count-reached |
edms.storage.size |
instant |
infra_metering_read-edms-storage-size |
infra_quota_check-edms-storage-size-availability |
infra_quota_handle-edms-storage-size-reached |
google.docai.calls.count |
period |
infra_metering_read-google-docai-calls-count |
- | infra_quota_handle-google-docai-calls-count-reached |
auth.users.count |
instant |
infra_metering_read-instance-users-count |
infra_quota_check-auth-users-count-availability |
infra_quota_handle-instance-users-count-reached |
email.outbound.count |
period |
infra_metering_read-mail-outbound-count |
- | infra_quota_handle-mail-outbound-count-reached |
db.storage.size |
instant |
infra_metering_read-db-storage-size |
- | infra_quota_handle-db-storage-size-reached |
Tâches planifiées et santé de l'instance¶
Les tâches suivantes sont attendues dans le contrôle de santé de l'instance :
infra_quota_refresh-valuesinfra_quota_shift-periods
infra_quota_refresh-values maintient les valeurs et seuils à jour.
infra_quota_shift-periods réinitialise les fenêtres temporelles des quotas périodiques expirés.
Ces tâches sont vérifiées par infra_server_refresh-self-status.
Recommandations de configuration¶
Pour les PO¶
- Définir une limite claire par quota actif.
- Utiliser un seuil bloquant uniquement lorsqu'un dépassement doit empêcher l'opération.
- Préférer
trigger_policy = on_reachpour les notifications ou alertes. - Utiliser
trigger_policy = alwaysseulement si l'action peut être rejouée sans effet indésirable. - Documenter la décision métier lorsque
is_activeest mis àfalse.
Pour les DEV¶
- Garder les providers de disponibilité légers.
- Ne pas appeler les collecteurs complets depuis
check-availability. - Garder les collecteurs dans
infra_metering_*et les contrôles candidats dansinfra_quota_check-*. - Utiliser
Quota::search(...)->do('check-availability', $values)dans lescancreate()ou workflows équivalents. - S'assurer que chaque
MetricDefinition.collector,Quota.availability_controlleretQuotaThreshold.actionpointe vers un contrôleur existant. - Préférer des actions de seuil idempotentes, surtout avec
trigger_policy = always.
Fichiers de référence¶
Classes :
packages/infra/classes/metering/MetricDefinition.class.phppackages/infra/classes/quota/Quota.class.phppackages/infra/classes/quota/QuotaThreshold.class.php
Actions :
packages/infra/actions/quota/refresh-values.phppackages/infra/actions/quota/shift-periods.phppackages/infra/actions/quota/handle-*.php
Providers :
packages/infra/data/metering/read-*.phppackages/infra/data/quota/check-*-availability.php
Initialisation et updates :
packages/fmt/init/data/scripts/30-create-infra_quotas.phppackages/fmt/init/updates/20260806104500_update_infra_quota_controllers.php