@@ -100,27 +100,46 @@ public static function pullPending(array $attributes = []): Model&Tenant
100100 */
101101 public static function pullPendingFromPool (bool $ firstOrCreate = false , array $ attributes = []): ?Tenant
102102 {
103- $ tenant = DB :: transaction ( function () use ( $ attributes ): ? Tenant {
104- /** @var (Model&Tenant)|null $ tenant */
105- $ tenant = static :: onlyPending ()-> first ();
106-
107- if ( $ tenant !== null ) {
108- event ( new PullingPendingTenant ( $ tenant ) );
109- $ tenant -> update ( array_merge ( $ attributes , [
110- ' pending_since ' => null ,
111- ])) ;
103+ // Attempt pulling a pending tenant.
104+ // The loop handles the case where a single tenant is being pulled by multiple processes at the same time.
105+ // If a tenant was pulled by a concurrent process, try pulling the next one in the pool.
106+ while ( true ) {
107+ /** @var (Model&Tenant)|null $pullCandidate */
108+ $ pullCandidate = static :: onlyPending ()-> first ( );
109+
110+ if ( $ pullCandidate === null ) {
111+ return $ firstOrCreate ? static :: create ( $ attributes ) : null ;
112112 }
113113
114- return $ tenant ;
115- });
114+ event (new PullingPendingTenant ($ pullCandidate ));
116115
117- if ($ tenant === null ) {
118- return $ firstOrCreate ? static ::create ($ attributes ) : null ;
119- }
116+ $ tenant = DB ::transaction (function () use ($ pullCandidate , $ attributes ): ?Tenant {
117+ $ tenantWasPulled = static ::onlyPending ()
118+ ->whereKey ($ pullCandidate ->getKey ())
119+ ->update ([$ pullCandidate ->getColumnForQuery ('pending_since ' ) => null ]) > 0 ;
120+
121+ if (! $ tenantWasPulled ) {
122+ return null ;
123+ }
124+
125+ /** @var Model&Tenant $pulledTenant */
126+ $ pulledTenant = static ::findOrFail ($ pullCandidate ->getKey ());
127+
128+ if (! empty ($ attributes )) {
129+ $ pulledTenant ->update ($ attributes );
130+ }
120131
121- // Only triggered if a tenant that was pulled from the pool is returned
122- event ( new PendingTenantPulled ( $ tenant ) );
132+ return $ pulledTenant ;
133+ } );
123134
124- return $ tenant ;
135+ if ($ tenant === null ) {
136+ // If another pull claimed this tenant first, try claiming the next one
137+ continue ;
138+ }
139+
140+ event (new PendingTenantPulled ($ tenant ));
141+
142+ return $ tenant ;
143+ }
125144 }
126145}
0 commit comments