PHPackages                             laragear/attempt-once - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. laragear/attempt-once

ArchivedLibrary[Utility &amp; Helpers](/categories/utility)

laragear/attempt-once
=====================

Run and manage callbacks across multiple app instances

v1.0.0(3mo ago)10[3 PRs](https://github.com/Laragear/AttemptOnce/pulls)MITPHPPHP ^8.4CI passing

Since Jan 15Pushed 2mo agoCompare

[ Source](https://github.com/Laragear/AttemptOnce)[ Packagist](https://packagist.org/packages/laragear/attempt-once)[ Fund](https://github.com/sponsors/DarkGhostHunter)[ Fund](https://paypal.me/darkghosthunter)[ RSS](/packages/laragear-attempt-once/feed)WikiDiscussions 1.x Synced 1mo ago

READMEChangelog (1)Dependencies (4)Versions (5)Used By (0)

Deprecated
==========

[](#deprecated)

Use [`Cache::funnel()`](https://github.com/laravel/framework/pull/58439) with 1 attempt instead.

Once
====

[](#once)

[![Latest Version on Packagist](https://camo.githubusercontent.com/03ca31d14d17dee9155741e360f94633575bd561afbc7d7b2b041a14e3c498df/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c617261676561722f617474656d70742d6f6e63652e737667)](https://packagist.org/packages/laragear/attempt-once)[![Latest stable test run](https://github.com/Laragear/AttemptOnce/actions/workflows/php.yml/badge.svg?branch=1.x)](https://github.com/Laragear/AttemptOnce/actions/workflows/php.yml)[![Codecov coverage](https://camo.githubusercontent.com/1a155168b28b38da4ca4b48f6cf24251b129874ed4f7ee0b50ea3449ca85d6b8/68747470733a2f2f636f6465636f762e696f2f67682f4c617261676561722f417474656d70744f6e63652f6272616e63682f312e782f67726170682f62616467652e7376673f746f6b656e3d49386331684742747163)](https://codecov.io/gh/Laragear/AttemptOnce)[![Maintainability](https://camo.githubusercontent.com/7bcb3dcd1ce3cc9320d04565ec5e72491ad5f801eecfcf7360193624f40af31b/68747470733a2f2f716c74792e73682f67682f4c617261676561722f70726f6a656374732f417474656d70744f6e63652f6d61696e7461696e6162696c6974792e737667)](https://qlty.sh/gh/Laragear/projects/AttemptOnce)[![Sonarcloud Status](https://camo.githubusercontent.com/6b59a7cda58a72c0034ed6f21d1b07c86fd0c834537ae0cadbb267e95f6be39a/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d4c617261676561725f417474656d70744f6e6365266d65747269633d616c6572745f737461747573)](https://sonarcloud.io/dashboard?id=Laragear_AttemptOnce)[![Laravel Octane Compatibility](https://camo.githubusercontent.com/70359a356da237cd29561bc5d0bb80baae775b5ff62f288ed324755382858342/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2532304f6374616e652d436f6d70617469626c652d737563636573733f7374796c653d666c6174266c6f676f3d6c61726176656c)](https://laravel.com/docs/12.x/octane#introduction)

Run and manage callbacks across multiple app instances, atomically.

```
use App\Mails\Newsletter;

attempt_once(function () => {
    Newsletter::send();
});
```

Become a sponsor
----------------

[](#become-a-sponsor)

[![](.github/assets/support.png)](https://github.com/sponsors/DarkGhostHunter)

Your support allows me to keep this package free, up-to-date and maintainable.

Requirements
------------

[](#requirements)

- PHP 8.4
- Laravel 11 or later

Installation
------------

[](#installation)

You can install the package via Composer.

```
composer require laragear/once
```

How does this work?
-------------------

[](#how-does-this-work)

It uses Laravel's Rate Limiter behind the scenes to allow callbacks to run once. This way all app instances are *aware* of the callback execution, ensuring only runs once inside a given window of time, which is 1 minute by default.

Usage
-----

[](#usage)

The simplest way to use `attempt_once()` is to just issue a callback, which will be executed only once for 30 seconds. A key will be computed from the callback as `laragear|attempt_once:{hash}` based on the callback unique position in your application.

```
attempt_once(function () {
    // ... do something.
})
```

Adding a second argument after the callback will set the amount of time to "hold" the execution. You may use a `DateTimeInterface` instance, a `DateInterval` object or just an amount of seconds.

```
attempt_once(function () {
    // ... do something.
}, now()->addMinute())
```

Important

When using a single callback, the hash computed takes into account the place where is called. Duplicating the code **will make both callbacks hashes different**, even if they do exactly the same.

While the above may suffice for most simple scenarios, you may have more granular control on the execution by calling `attempt_once()` with a key to identify the execution, or a string backed enum. You will receive a builder instance to configure how to run it:

```
$result = attempt_once('send-email')->in(60)->run(function () {
    // ...
});

use App\Enums\EmailType;

$result = attempt_once(EmailType::Transactional)->in(60)->run(function () {
    // ...
});
```

### Custom key

[](#custom-key)

The `attempt_once()` method allows to identify the callback to run once with a simple string. With a constant string, you may [check the execution status elsewhere in your app](#checking-execution).

```
attempt_once('send-email')->run(function () {
    // ...
});
```

You can issue multiple strings or arrays, which is great when you need to separate executions programmatically. The resulting key will be concatenated using `|`. If you pass an array, the key and value will be concatenated as `{key}:{value}`.

```
// "send-email|transaction|user:1"
attempt_once('send-email', 'transaction', ['user' => 1])->run(function () {
    // ...
});
```

If you pass an Eloquent Model as second parameter, it will be used to identify the callback as `{class}:{key}`, essentially making the callback unique for each model you pass.

```
use App\Models\User;

$user = User::find(1);

// "send-email|\App\Models\User:1"
attempt_once('send-email', $user)->run(function () {
    // ...
});
```

When using an Enum as key, the class name and case name will be used as part of the key as `{class}:{case}`.

```
use App\Models\User;
use App\Enums\EmailType;

$user = User::find(1);

// "send-email|\App\Enums\EmailType:Transactional|\App\Models\User:1"
attempt_once('send-email', EmailType::Transactional)->run(function () {
    // ...
});
```

### Time

[](#time)

You may change the window of time using `for()` with the amount of seconds. You may also use `DateTimeInterface` instance, or a `DateInterval` instance.

```
use function Illuminate\Support\seconds;

// Using seconds
attempt_once('send-email')->for(30)->run(function () {
    // ...
});

// Using a DateTimeInterface, like a Carbon instance
attempt_once('send-email')->for(now()->addSeconds(30))->run(function () {
    // ...
});

// Using a DateInterval, like the `seconds()` helper.
attempt_once('send-email')->for(seconds(30))->run(function () {
    // ...
});
```

Important

You *may* change the window of time programmatically, but consider that only previous successful execution will set the time. Since subsequent executions won't run, the time won't be updated.

Callback result
---------------

[](#callback-result)

When the callback runs, its result will be returned. When the callback does not run because it's rate limited, `false` will be returned.

```
use App\Models\Article;
use Illuminate\Support\Facades\Route;

Route::get('/articles/all', function () {
    $articles = attempt_once(function () {
        return Article::limit(10)->latest()->get();
    });

    // Check the callback was not executed
    if ($articles === false) {
        return 'You need to wait 30 seconds to retrieve more articles';
    }

    return $articles;
});
```

### Default result

[](#default-result)

Sometimes you will want to return another value rather than `false` if the callback is not executed. For that, use the `or()` method.

```
use App\Models\Article;
use function Illuminate\Support\minutes;

$collection = attempt_once('latest-articles')
    ->or(new Collection())
    ->run(function () {
        return Article::limit(10)->latest()->get();
    });
```

### Checking execution

[](#checking-execution)

To check if the callback was executed, you may use the `wasExecuted()` and `wasNotExecuted()` methods, which is only accessible using a named key.

```
if (attempt_once('send-email')->wasExecuted()) {
    return 'An email was already sent!';
}

if (attempt_once('send-email')->wasNotExecuted()) {
    return 'You can send a new email now';
}
```

To check how many seconds remain to execute the callback again, use `availableIn()`, or `readyAt()` to get a Carbon instance.

```
$seconds = attempt_once('send-email')->availableIn();

echo "You can send a new email in $seconds seconds.";

$datetime = attempt_once('send-email')->readyAt();

echo "You can send a new email at $datetime."
```

### Cache Store

[](#cache-store)

By default, Laravel's Rate Limiter uses the application default cache store. If you want to change the cache store to use, [configure the Rate Limiter in your app configuration](https://laravel.com/docs/12.x/rate-limiting#cache-configuration).

Laravel Octane compatibility
----------------------------

[](#laravel-octane-compatibility)

- There are no singletons using a stale app instance.
- There are no singletons using a stale config instance.
- There are no singletons using a stale request instance.
- There are no static properties written during a request.

There should be no problems using this package with Laravel Octane.

Security
--------

[](#security)

If you discover any security-related issues, issue a [Security Advisory](https://github.com/Laragear/Once/security/advisories/new).

License
=======

[](#license)

This specific package version is licensed under the terms of the [MIT License](LICENSE.md), at the time of publishing.

[Laravel](https://laravel.com) is a Trademark of [Taylor Otwell](https://github.com/TaylorOtwell/). Copyright © 2011-2026 Laravel LLC.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance83

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~48 days

Total

2

Last Release

65d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5141911?v=4)[Italo](/maintainers/DarkGhostHunter)[@DarkGhostHunter](https://github.com/DarkGhostHunter)

---

Top Contributors

[![DarkGhostHunter](https://avatars.githubusercontent.com/u/5141911?v=4)](https://github.com/DarkGhostHunter "DarkGhostHunter (11 commits)")

### Embed Badge

![Health badge](/badges/laragear-attempt-once/health.svg)

```
[![Health](https://phpackages.com/badges/laragear-attempt-once/health.svg)](https://phpackages.com/packages/laragear-attempt-once)
```

###  Alternatives

[laragear/two-factor

On-premises 2FA Authentication for out-of-the-box.

339785.3k8](/packages/laragear-two-factor)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
