refactor(shoraka): move financing records to master database
This commit is contained in:
@@ -52,3 +52,10 @@ MYKAD_READER_ENABLED_CAWANGAN=''
|
||||
INTERNAL_NOTIFICATION_SECRET=
|
||||
|
||||
LOGVIEWER_PASSWORD=
|
||||
|
||||
# Same master database as api_arrahn mysql7; required for financing records.
|
||||
SHORAKA_MASTER_DB_HOST=
|
||||
SHORAKA_MASTER_DB_PORT=3306
|
||||
SHORAKA_MASTER_DB_DATABASE=
|
||||
SHORAKA_MASTER_DB_USERNAME=
|
||||
SHORAKA_MASTER_DB_PASSWORD=
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use RuntimeException;
|
||||
|
||||
class MoveShorakaFinancings extends Command
|
||||
{
|
||||
protected $signature = 'shoraka:move-financings {--source=mysql} {--apply : Copy records; default only checks}';
|
||||
protected $description = 'Copy and verify financing records to shoraka_master without deleting the source';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$sourceName = $this->option('source');
|
||||
$targetName = 'shoraka_master';
|
||||
$source = DB::connection($sourceName);
|
||||
$target = DB::connection($targetName);
|
||||
if ($sourceName === $targetName || ($source->getConfig('host') === $target->getConfig('host')
|
||||
&& $source->getDatabaseName() === $target->getDatabaseName()
|
||||
&& $source->getConfig('port') === $target->getConfig('port'))) {
|
||||
$this->error('Source and target must be different databases.');
|
||||
return 1;
|
||||
}
|
||||
if (!Schema::connection($sourceName)->hasTable('shoraka_financings')
|
||||
|| !Schema::connection($targetName)->hasTable('shoraka_financings')) {
|
||||
$this->error('Create the target table using the API master migration first. Source and target tables are required.');
|
||||
return 1;
|
||||
}
|
||||
if ($this->option('apply') && !app()->isDownForMaintenance()) {
|
||||
$this->error('Stop traffic on every counter instance and run artisan down before applying the transfer.');
|
||||
return 1;
|
||||
}
|
||||
if ($source->table('shoraka_financings')->where('state', 'PROCESSING')->exists()) {
|
||||
$this->error('PROCESSING records require reconciliation before transfer.');
|
||||
return 1;
|
||||
}
|
||||
$count = $source->table('shoraka_financings')->count();
|
||||
if (!$this->option('apply')) {
|
||||
$this->info($count . ' source records. Check only; no data was copied.');
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
$target->transaction(function () use ($source, $target) {
|
||||
$source->table('shoraka_financings')->orderBy('id')->chunkById(200, function ($rows) use ($target) {
|
||||
foreach ($rows as $row) {
|
||||
$data = (array) $row;
|
||||
unset($data['id']); // IDs may overlap across counter databases.
|
||||
$key = ['kodcaw' => $row->kodcaw, 'norujukan' => $row->norujukan];
|
||||
$existing = $target->table('shoraka_financings')->where($key)->first();
|
||||
if (!$existing) {
|
||||
$target->table('shoraka_financings')->insert($data);
|
||||
$existing = $target->table('shoraka_financings')->where($key)->first();
|
||||
}
|
||||
foreach ($data as $field => $value) {
|
||||
$actual = $existing->$field;
|
||||
if ($field === 'context') {
|
||||
if (json_decode($actual, true) != json_decode($value, true)) {
|
||||
throw new RuntimeException('Conflicting context: ' . $row->kodcaw . '/' . $row->norujukan);
|
||||
}
|
||||
} elseif ((string) $actual !== (string) $value) {
|
||||
throw new RuntimeException('Conflicting field ' . $field . ': ' . $row->kodcaw . '/' . $row->norujukan);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error('Transfer rolled back. ' . $exception->getMessage());
|
||||
return 1;
|
||||
}
|
||||
$this->info($count . ' source records copied and verified. Source retained.');
|
||||
$this->info('Ensure shoraka.financing_connection is shoraka_master and reload configuration before reopening traffic.');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,11 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ShorakaFinancing extends Model
|
||||
{
|
||||
public function getConnectionName()
|
||||
{
|
||||
return $this->connection ?: config('shoraka.financing_connection');
|
||||
}
|
||||
|
||||
protected $guarded = [];
|
||||
protected $casts = ['context' => 'array'];
|
||||
}
|
||||
|
||||
@@ -63,6 +63,22 @@ return [
|
||||
]) : [],
|
||||
],
|
||||
|
||||
// Point these settings at the same database as api_arrahn's mysql7.
|
||||
'shoraka_master' => [
|
||||
'driver' => 'mysql',
|
||||
'host' => env('SHORAKA_MASTER_DB_HOST'),
|
||||
'port' => env('SHORAKA_MASTER_DB_PORT', '3306'),
|
||||
'database' => env('SHORAKA_MASTER_DB_DATABASE'),
|
||||
'username' => env('SHORAKA_MASTER_DB_USERNAME'),
|
||||
'password' => env('SHORAKA_MASTER_DB_PASSWORD'),
|
||||
'unix_socket' => env('SHORAKA_MASTER_DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
// Financing workflow records are centralized in API mysql7's master database.
|
||||
// Never fall back to the counter database when the master is unavailable.
|
||||
'financing_connection' => 'shoraka_master',
|
||||
];
|
||||
+11
-2
@@ -2,7 +2,14 @@ FROM php:7.4-fpm AS base
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
RUN apt-get update \
|
||||
# PHP 7.4 uses Debian Bullseye; use its archived package repositories.
|
||||
# Archived security metadata expires, but package signatures remain verified.
|
||||
RUN printf '%s\n' \
|
||||
'deb https://archive.debian.org/debian bullseye main' \
|
||||
'deb [check-valid-until=no] https://archive.debian.org/debian-security bullseye-security main' \
|
||||
> /etc/apt/sources.list \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get -o Acquire::Retries=3 update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
pkg-config \
|
||||
@@ -28,7 +35,9 @@ COPY docker/php/php.ini /usr/local/etc/php/conf.d/app.ini
|
||||
COPY docker/php/zz-clear-env.conf /usr/local/etc/php-fpm.d/zz-clear-env.conf
|
||||
COPY docker/php/entrypoint.sh /usr/local/bin/app-entrypoint.sh
|
||||
|
||||
RUN chmod +x /usr/local/bin/app-entrypoint.sh \
|
||||
# Normalize Windows checkout line endings before executing the script.
|
||||
RUN sed -i 's/\r$//' /usr/local/bin/app-entrypoint.sh \
|
||||
&& chmod +x /usr/local/bin/app-entrypoint.sh \
|
||||
&& usermod -u 1000 www-data && groupmod -g 1000 www-data
|
||||
|
||||
ENTRYPOINT ["app-entrypoint.sh"]
|
||||
|
||||
Reference in New Issue
Block a user