Shared\Flag

OxPHP\Shared\Flag est un booléen atomique à l'échelle du processus — le jumeau booléen de Shared\Atomic. Chaque opération est sans verrou ; deux workers qui inversent le drapeau simultanément ne peuvent pas observer d'état intermédiaire.

Vue d'ensemble

  • Booléen atomique. Un seul bit d'état, avec load / store / swap / compareAndSet.
  • Ordonnancement mémoire explicite. Chaque opération accepte un Ordering optionnel, dont la valeur par défaut est SeqCst, exactement comme Shared\Atomic.
  • Sans verrou. Toutes les mutations tiennent en une seule instruction atomique du CPU. Sûr en cas de contention.
  • Partageable. Les instances vivent dans le registre et peuvent être stockées dans un Shared\Map, transmises via des captures use, etc.

Référence de l'API

php
namespace OxPHP\Shared; final class Flag implements Shareable { public function __construct(bool $initial = false); public function load(Ordering $order = Ordering::SeqCst): bool; // Relaxed | Acquire | SeqCst public function store(bool $value, Ordering $order = Ordering::SeqCst): void; // Relaxed | Release | SeqCst public function swap(bool $value, Ordering $order = Ordering::SeqCst): bool; // any ordering; returns previous public function compareAndSet( bool $expect, bool $new, Ordering $success = Ordering::SeqCst, Ordering $failure = Ordering::SeqCst, // Relaxed | Acquire | SeqCst ): bool; public function id(): int; }
Méthode Retour Cas d'usage
load actuelle Simple lecture.
store void Affecte une valeur explicite sans condition.
swap précédente Affecte une valeur explicite ; la valeur de retour indique si vous l'avez modifiée. swap(true) est un test-and-set (« ai-je gagné ? »).
compareAndSet échangé ? Initialisation one-shot : ne réussit que si le drapeau valait la valeur attendue.

Exemples

Kill-switch

php
<?php use OxPHP\Shared\Flag; $maintenance = new Flag(); // In a request handler if ($maintenance->load()) { http_response_code(503); header('Retry-After: 60'); echo 'under maintenance'; return; } // In an admin endpoint $maintenance->store(true); // enable $maintenance->store(false); // disable

Vainqueur de l'initialisation one-shot

php
<?php use OxPHP\Shared\Flag; $migrated = new Flag(); if ($migrated->compareAndSet(expect: false, new: true)) { // First worker to arrive wins — run the migration once. runSchemaMigration(); } else { // Someone else already ran it. }

Déclenchement du circuit breaker

php
<?php use OxPHP\Shared\Flag; $tripped = new Flag(); try { callDownstream(); } catch (DownstreamFailedException $e) { $wasAlreadyTripped = $tripped->swap(true); // set true, learn the prior state if (!$wasAlreadyTripped) { alertOncall($e); // fire alert only on first trip } throw $e; }

Pour un circuit breaker complet, vous aurez généralement besoin d'un Shared\Counter pour la fenêtre d'échecs et d'un Shared\Flag pour l'état déclenché — réinitialisez le drapeau via store(false) une fois que la fenêtre est retombée au calme.

Publier une charge utile, puis signaler avec un ordonnancement moins coûteux

php
<?php use OxPHP\Shared\Flag; use OxPHP\Shared\Map; use OxPHP\Shared\Ordering; $ready = new Flag(); $config = new Map(); // Producer: write the payload, then publish with Release. $config->set('dsn', $dsn); $ready->store(true, Ordering::Release); // Consumer: an Acquire load that observes `true` also observes the payload. if ($ready->load(Ordering::Acquire)) { $dsn = $config->get('dsn'); }

Sémantique et pièges

swap renvoie la valeur précédente, qui est le retour le plus utile : « ai-je changé quelque chose ? » se résume à $prev !== $new, et swap(true) est le test-and-set canonique. store renvoie void ; si vous avez besoin de la valeur antérieure, utilisez swap.

compareAndSet est la façon d'exprimer « le premier arrivé l'emporte ». Un simple store(true) réussit toujours, il ne peut donc pas exprimer « ne pas écraser si la valeur est déjà définie ».

Ordonnancement mémoire

L'ordonnancement mémoire est identique à celui de Shared\Atomic. load rejette Release/AcqRel, store rejette Acquire/AcqRel, et le $failure de compareAndSet rejette Release/AcqRel — chacun lève une InvalidOrderingException. La valeur par défaut SeqCst est toujours sûre.

Aucune attente

Un drapeau ne bloque pas. Si vous devez attendre une transition, associez-le à un Shared\Channel ou utilisez Shared\Once.

Exceptions

Exception Levée par
StaleHandleException Toute méthode sur un handle dont l'entrée de registre a été évincée.
UninitializedException id() sur un wrapper dont le __construct n'est pas terminé.
InvalidOrderingException Un Ordering non autorisé pour l'opération (voir ci-dessus).

Observabilité

Voir Observabilité de l'état partagé. Références rapides :

  • GET /__ox_shared/entry?id=N expose { value: true|false, type: "Flag" }.
  • Jauge Prometheus oxphp_shared_flag_value{flag_id="…"} (0 ou 1).
  • Les métriques à l'échelle du registre couvrent Flag via le label type="Flag".

Quand ne pas l'utiliser

  • Logique à plusieurs états. Un drapeau n'a que deux valeurs. S'il vous faut idle/busy/done ou toute machine à trois états, tournez-vous vers Shared\Counter (avec des valeurs d'enum entières) ou Shared\Mutex sur un tableau façon enum.
  • Attendre une transition. Les drapeaux ne bloquent pas. Associez-le à un Shared\Channel (ou à un Shared\Counter que vous interrogez par compareAndSet) lorsqu'un worker doit attendre que le drapeau s'inverse.
  • Compter des événements. Un drapeau n'est pas un compteur. Utilisez Shared\Counter pour les décomptes.
  • État entier. Si le commutateur est en réalité un petit entier, utilisez directement Shared\Atomic.

Prompts pour votre agent

Ces prompts supposent un agent connecté au serveur MCP de la documentation OxPHP — il lira lui-même les pages dont il a besoin.

prompt
Utilise un Shared Flag d'OxPHP dans mon code à la place de l'interrupteur de mode maintenance ou de circuit breaker que je garde aujourd'hui dans une variable d'environnement ou un fichier de configuration. Lis la page `shared-state/shared-flag` via le serveur MCP de la documentation OxPHP. Trouve cet interrupteur dans ce dépôt et montre-moi le remplacement par un Flag, plus le seul point d'appel qui devrait être un `compareAndSet` plutôt qu'un `store` inconditionnel.

Voir aussi

  • État partagé — vue d'ensemble et modèle mental.
  • Shared\Atomic — le jumeau int64, même modèle d'ordonnancement.
  • Shared\Counter — quand vous avez besoin de plus que on/off.
  • Shared\Once — quand la valeur calculée une seule fois est plus riche qu'un booléen.
  • Shared\Mutex — quand l'inversion d'un drapeau doit être validée conjointement avec un autre état.
Une erreur ? Signalez-la →