新增 主机 锁定 和 不可用状态

This commit is contained in:
iVampireSP.com 2023-01-20 16:05:12 +08:00
parent 6f6f5669e4
commit a7ade7843d
No known key found for this signature in database
GPG Key ID: 2F7B001CA27A8132
13 changed files with 207 additions and 87 deletions

View File

@ -2,10 +2,10 @@
namespace App\Console;
use App\Jobs\Host\DeleteSuspendedHostJob;
use App\Jobs\Host\DeleteHostJob;
use App\Jobs\Host\DispatchHostCostQueueJob;
use App\Jobs\Host\ScanAllHostsJob;
use App\Jobs\Module\FetchModuleJob;
use App\Jobs\Module\DispatchFetchModuleJob;
use App\Jobs\Module\SendModuleEarningsJob;
use App\Jobs\User\CheckAndChargeBalanceJob;
use App\Jobs\User\ClearTasksJob;
@ -33,8 +33,8 @@ protected function schedule(Schedule $schedule): void
// 扣费
$schedule->job(new DispatchHostCostQueueJob(now()->minute))->everyMinute()->withoutOverlapping()->onOneServer();
// 获取模块暴露的信息(服务器等
$schedule->job(new FetchModuleJob())->withoutOverlapping()->everyMinute();
// 获取模块暴露的信息(服务器等,检查模块状态
$schedule->job(new DispatchFetchModuleJob())->withoutOverlapping()->everyMinute();
// 推送工单
$schedule->job(new PushWorkOrderJob())->everyMinute()->onOneServer();
@ -45,7 +45,7 @@ protected function schedule(Schedule $schedule): void
$schedule->job(new ClearTasksJob())->weekly();
// 删除暂停或部署时间超过 3 天以上的主机
$schedule->job(new DeleteSuspendedHostJob())->hourly();
$schedule->job(new DeleteHostJob())->hourly();
// 检查主机是否存在于模块
$schedule->job(new ScanAllHostsJob())->everyThirtyMinutes()->withoutOverlapping()->onOneServer();

View File

@ -58,7 +58,7 @@ public function update(Request $request, Host $host): RedirectResponse
{
$request->validate([
'name' => 'sometimes|string|max:255',
'status' => 'sometimes|in:running,stopped,suspended,pending',
'status' => 'sometimes|in:running,stopped,suspended,pending,locked,unavailable',
'price' => 'sometimes|numeric',
'managed_price' => 'nullable|numeric',
]);

View File

@ -30,6 +30,10 @@ public function update(HostRequest $request, Host $host): JsonResponse
'status' => 'required|in:running,stopped',
]);
if ($host->status === 'locked' || $host->status === 'unavailable') {
return $this->error('当前主机状态不允许操作');
}
$user = $request->user();
if ($user->balance < 0.5) {

View File

@ -7,6 +7,7 @@
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cache;
class ModuleController extends Controller
{
@ -17,6 +18,13 @@ public function index(): JsonResponse
return $this->success($modules);
}
public function servers(Module $module): JsonResponse
{
$servers = Cache::get('module:' . $module->id . ':servers', []);
return $this->success($servers);
}
public function call(Request $request, Module $module): JsonResponse|Response
{
return (new \App\Http\Controllers\Module\ModuleController())->call($request, $module);

View File

@ -10,7 +10,7 @@
// use Illuminate\Contracts\Queue\ShouldBeUnique;
class DeleteSuspendedHostJob implements ShouldQueue
class DeleteHostJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
@ -44,5 +44,19 @@ public function handle(): void
dispatch(new HostJob($host, 'delete'));
}
});
// 查找不可用时间超过 3 天以上的 host
(new Host)->where('status', 'unavailable')->where('unavailable_at', '<', now()->subDays(3))->chunk(100, function ($hosts) {
foreach ($hosts as $host) {
dispatch(new HostJob($host, 'delete'));
}
});
// 查找锁定时间超过 3 天以上的 host
(new Host)->where('status', 'locked')->where('locked_at', '<', now()->subDays(3))->chunk(100, function ($hosts) {
foreach ($hosts as $host) {
dispatch(new HostJob($host, 'delete'));
}
});
}
}

View File

@ -38,6 +38,13 @@ public function __construct(HostModel $host, $type = 'post')
public function handle(): void
{
$host = $this->host;
// 忽略 unavailable 状态的 host
if ($host->status === 'unavailable') {
return;
}
$host->load(['module']);
switch ($this->type) {

View File

@ -11,7 +11,7 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
class UpdateOrSuspendedHostJob implements ShouldQueue
class UpdateOrDeleteHostJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
@ -41,8 +41,10 @@ public function handle(): void
if ($response['status'] === 200) {
$host->update(Arr::except($response['json'], ['id', 'user_id', 'module_id', 'created_at', 'updated_at']));
} else if ($response['status'] === 404) {
Log::warning($host->module->name . ' ' . $host->name . ' ' . $host->id . ' 不存在,标记为暂停。');
dispatch(new HostJob($host, 'delete'));
Log::warning($host->module->name . ' ' . $host->name . ' ' . $host->id . ' 不存在,标记为不可用。');
// dispatch(new HostJob($host, 'delete'));
$host->status = 'unavailable';
$host->save();
}
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Jobs\Module;
use App\Models\Module;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class DispatchFetchModuleJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle(): void
{
(new Module)->whereNotNull('url')->chunk(100, function ($modules) {
foreach ($modules as $module) {
dispatch(new FetchModuleJob($module));
}
});
}
}

View File

@ -2,10 +2,12 @@
namespace App\Jobs\Module;
use App\Jobs\Host\UpdateOrDeleteHostJob;
use App\Models\Module;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;
@ -13,16 +15,19 @@
class FetchModuleJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected Module $module;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
public function __construct(Module $module)
{
//
$this->module = $module;
}
/**
@ -32,30 +37,18 @@ public function __construct()
*/
public function handle(): void
{
// 获取运行完成的时间
$module = $this->module;
// $last_run = Cache::get('servers_updated_at', false);
// if ($last_run !== false) {
// // 如果和上次运行时间间隔小于一分钟,则不运行
// if (now()->diffInMinutes($last_run) < 1) {
// return;
// }
// }
$servers = Cache::get('module:' . $module->id . ':servers', []);
//
(new Module)->whereNotNull('url')->chunk(100, function ($modules) {
$servers = [];
foreach ($modules as $module) {
try {
$response = $module->http()->get('remote');
} catch (Exception $e) {
Log::error($e->getMessage());
continue;
return;
}
if ($response->successful()) {
// 如果模块状态不为 up则更新为 up
if ($module->status !== 'up') {
$module->status = 'up';
@ -83,9 +76,9 @@ public function handle(): void
}
} else {
// if module return maintenance, then set module status to maintenance
if ($response->status() == 503) {
$status = $response->status();
if ($status == 503 || $status == 429 || $status == 502) {
$module->status = 'maintenance';
} else {
$module->status = 'down';
@ -93,17 +86,13 @@ public function handle(): void
}
$module->save();
}
// if local
if (config('app.env') === 'local') {
Cache::forever('servers', $servers);
Cache::forever('module:' . $module->id . ':servers', $servers);
} else {
Cache::put('servers', $servers, now()->addMinutes(10));
Cache::put('module:' . $module->id . ':servers', $servers, now()->addMinutes(10));
}
// 缓存运行完成的时间
// Cache::put('servers_updated_at', now(), now()->addMinutes(10));
});
}
}

View File

@ -4,7 +4,7 @@
use App\Events\Users;
use App\Jobs\Host\HostJob;
use App\Jobs\Host\UpdateOrSuspendedHostJob;
use App\Jobs\Host\UpdateOrDeleteHostJob;
use App\Notifications\WebNotification;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Collection;
@ -54,23 +54,35 @@ protected static function boot()
});
static::created(function (self $model) {
$model->user->notify(new WebNotification($model, 'hosts.created'));
});
static::updating(function ($model) {
static::updating(function (self $model) {
if ($model->isDirty('status')) {
if ($model->status == 'suspended') {
$model->suspended_at = now();
} else {
$model->suspended_at = null;
}
if ($model->status == 'locked') {
$model->locked_at = now();
} else {
$model->locked_at = null;
}
if ($model->status == 'unavailable') {
$model->unavailable_at = now();
} else {
$model->unavailable_at = null;
}
}
// 调度任务
if ($model->status !== 'unavailable') {
dispatch(new HostJob($model, 'patch'));
}
broadcast(new Users($model->user_id, 'hosts.updating', $model));
});
@ -307,7 +319,7 @@ public function addLog(string $amount = "0"): bool
public function updateOrDelete(): bool
{
dispatch(new UpdateOrSuspendedHostJob($this));
dispatch(new UpdateOrDeleteHostJob($this));
return true;
}

View File

@ -20,10 +20,9 @@ class Module extends Authenticatable
public $incrementing = false;
// primary key
public $timestamps = false;
protected $table = 'modules';
protected $keyType = 'string';
protected $fillable = [
'id',
'name',

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
\Illuminate\Support\Facades\DB::statement("ALTER TABLE `hosts` CHANGE `status` `status` ENUM('running','stopped','error','suspended','pending','unavailable', 'locked') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending';");
\Illuminate\Support\Facades\Schema::table('hosts', function (Blueprint $table) {
$table->timestamp('unavailable_at')->nullable()->comment('不可用时间')->after('suspended_at');
$table->timestamp('locked_at')->nullable()->comment('锁定时间')->after('unavailable_at');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
\Illuminate\Support\Facades\DB::statement("ALTER TABLE `hosts` CHANGE `status` `status` ENUM('running','stopped','error','suspended','pending') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending';");
\Illuminate\Support\Facades\Schema::table('hosts', function (Blueprint $table) {
$table->dropColumn('unavailable_at');
$table->dropColumn('locked_at');
});
}
};

View File

@ -20,6 +20,14 @@
<span class="badge bg-danger">错误</span>
@break
@case('unavailable')
<span class="badge bg-secondary">不可用</span>
@break
@case('locked')
<span class="badge bg-danger">锁定</span>
@break
@default
<span class="badge bg-secondary">{{ $status }}</span>
@endswitch