RESAZIP-PC\resaz

update ratelimit daitogooglechat

......@@ -126,6 +126,10 @@ This creates `config/daito-google-chat.php`.
```dotenv
DAITO_GOOGLE_CHAT_ENABLED=true
DAITO_GOOGLE_CHAT_WEBHOOK_URL=https://chat.googleapis.com/v1/spaces/.../messages?key=...&token=...
DAITO_GOOGLE_CHAT_QUEUE_NAME=google-chat
DAITO_GOOGLE_CHAT_RATE_LIMIT_ENABLED=true
DAITO_GOOGLE_CHAT_RATE_LIMIT_MAX_JOBS=20
DAITO_GOOGLE_CHAT_RATE_LIMIT_DECAY_SECONDS=60
```
### 3) Send immediately
......@@ -195,6 +199,41 @@ DaitoGoogleChat::sendCardV2($arrCardV2);
DaitoGoogleChat::queueCardV2($arrCardV2);
```
### 8) Anti-spam notes (recommended for production)
- Queue job is rate-limited globally by cache key (`daito-google-chat:webhook`).
- Default limit is `20` jobs / `60` seconds (configurable).
- Keep `queue_backoff_seconds` as-is to retry safely on transient errors.
Main config keys in `config/daito-google-chat.php`:
- `rate_limit_enabled`
- `rate_limit_max_jobs`
- `rate_limit_decay_seconds`
- `rate_limit_key`
- `queue_name` (default: `google-chat`)
### 9) Run dedicated queue worker for google-chat
Run a separate worker to isolate notification throughput:
```bash
php artisan queue:work --queue=google-chat --sleep=1 --tries=3 --timeout=30
```
Supervisor example:
```ini
[program:laravel-google-chat-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/artisan queue:work --queue=google-chat --sleep=1 --tries=3 --timeout=30
autostart=true
autorestart=true
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-google-chat-worker.log
```
## QueryLog (Laravel shared package)
> **Provider registration note**
......
......@@ -2,6 +2,7 @@
namespace Daito\Lib\DaitoGoogleChat\Jobs;
use Daito\Lib\DaitoGoogleChat\Middleware\DaitoGoogleChatRateLimitMiddleware;
use Daito\Lib\DaitoGoogleChat\Services\DaitoGoogleChatWebhookClient;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
......@@ -31,4 +32,15 @@ class DaitoGoogleChatWebhookJob implements ShouldQueue
{
$client->send($this->arrPayload, $this->webhookUrl);
}
public function middleware(): array
{
if (!(bool) config('daito-google-chat.rate_limit_enabled', true)) {
return array();
}
return array(
new DaitoGoogleChatRateLimitMiddleware(),
);
}
}
......
<?php
namespace Daito\Lib\DaitoGoogleChat\Middleware;
use Illuminate\Support\Facades\RateLimiter;
class DaitoGoogleChatRateLimitMiddleware
{
public function handle($job, $next): void
{
$rateLimitKey = (string) config('daito-google-chat.rate_limit_key', 'daito-google-chat:webhook');
$maxJobs = max(1, (int) config('daito-google-chat.rate_limit_max_jobs', 20));
$decaySeconds = max(1, (int) config('daito-google-chat.rate_limit_decay_seconds', 60));
if (RateLimiter::tooManyAttempts($rateLimitKey, $maxJobs)) {
$job->release(max(1, RateLimiter::availableIn($rateLimitKey)));
return;
}
RateLimiter::hit($rateLimitKey, $decaySeconds);
$next($job);
}
}
......@@ -12,8 +12,12 @@ return array(
'retry_times' => env('DAITO_GOOGLE_CHAT_RETRY_TIMES', 1),
'retry_sleep_ms' => env('DAITO_GOOGLE_CHAT_RETRY_SLEEP_MS', 200),
'queue_connection' => env('DAITO_GOOGLE_CHAT_QUEUE_CONNECTION', null),
'queue_name' => env('DAITO_GOOGLE_CHAT_QUEUE_NAME', null),
'queue_name' => env('DAITO_GOOGLE_CHAT_QUEUE_NAME', 'google-chat'),
'queue_tries' => env('DAITO_GOOGLE_CHAT_QUEUE_TRIES', 3),
'queue_backoff_seconds' => env('DAITO_GOOGLE_CHAT_QUEUE_BACKOFF', 10),
'rate_limit_enabled' => env('DAITO_GOOGLE_CHAT_RATE_LIMIT_ENABLED', true),
'rate_limit_max_jobs' => env('DAITO_GOOGLE_CHAT_RATE_LIMIT_MAX_JOBS', 20),
'rate_limit_decay_seconds' => env('DAITO_GOOGLE_CHAT_RATE_LIMIT_DECAY_SECONDS', 60),
'rate_limit_key' => env('DAITO_GOOGLE_CHAT_RATE_LIMIT_KEY', 'daito-google-chat:webhook'),
'throw_on_error' => env('DAITO_GOOGLE_CHAT_THROW_ON_ERROR', false),
);
......