Proof of concept - Vue Polling - Performance Improvement and tweaking for better user experience

This commit is contained in:
Dillon Ngo
2023-12-24 21:59:41 +08:00
parent 18df1c0c7b
commit 8ea00e0383
14 changed files with 333 additions and 31 deletions
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class RequestSignature implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('request_signature', $value);
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class ResultNotNull implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereNotNull('result');
}
}
@@ -4,7 +4,7 @@ namespace App\Classes\Modules\Jobs\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Jobs\Services\FetchesJobResult;
use App\Classes\Modules\Jobs\Processors\FetchesJobResultProcessor;
use App\Http\Resources\JobResultResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -22,16 +22,16 @@ class FetchJobResultLogic extends AbstractControllerLogic
];
}
/** @var FetchesJobResult */
private $fetchesJobResult;
/** @var FetchesJobResultProcessor */
private $fetchesJobResultProcessor;
/**
* FetchJobResultLogic constructor.
* @param FetchesJobResult $fetchesJobResult
* @param FetchesJobResultProcessor $fetchesJobResultProcessor
*/
public function __construct(FetchesJobResult $fetchesJobResult)
public function __construct(FetchesJobResultProcessor $fetchesJobResultProcessor)
{
$this->fetchesJobResult = $fetchesJobResult;
$this->fetchesJobResultProcessor = $fetchesJobResultProcessor;
}
@@ -44,10 +44,9 @@ class FetchJobResultLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$query = $this->fetchesJobResult->execute(['job_id' => $request->route('job_id')]);
$query = $this->fetchesJobResultProcessor->execute($request);
return $this->resourceResponse(new JobResultResource($query));
}
}
@@ -15,6 +15,12 @@ class ListGenericJobObject implements DataTransferObject
/** @var string */
private $jobId;
/** @var string */
private $requestSignature;
/** @var string */
private $resultSignature;
/** @var object */
private $userInfo;
@@ -24,11 +30,13 @@ class ListGenericJobObject implements DataTransferObject
/** @var string */
private $jobCommand;
public function __construct(string $name, array $payload, string $jobId, object $userInfo = null)
public function __construct(string $name, array $payload, string $requestSignature, ?string $resultSignature, string $jobId, object $userInfo = null)
{
$this->name = $name;
$this->payload = $payload;
$this->jobId = $jobId;
$this->requestSignature = $requestSignature;
$this->resultSignature = $resultSignature;
$this->userInfo = $userInfo;
}
@@ -56,6 +64,22 @@ class ListGenericJobObject implements DataTransferObject
return $this->jobId;
}
/**
* @return string
*/
public function getRequestSignature(): string
{
return $this->requestSignature;
}
/**
* @return string
*/
public function getResultSignature(): ?string
{
return $this->resultSignature;
}
/**
* @return object
*/
@@ -0,0 +1,60 @@
<?php
namespace App\Classes\Modules\Jobs\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class UpdateJobResultObject implements DataTransferObject
{
/** @var string */
private $result;
/** @var string */
private $resultSignature;
/** @var string */
private $jobCommandName;
/** @var string */
private $jobCommand;
public function __construct(string $result, string $resultSignature, string $jobCommandName, string $jobCommand)
{
$this->result = $result;
$this->resultSignature = $resultSignature;
$this->jobCommandName = $jobCommandName;
$this->jobCommand = $jobCommand;
}
/**
* @return string
*/
public function getResult(): string
{
return $this->result;
}
/**
* @return array
*/
public function getResultSignature(): string
{
return $this->resultSignature;
}
/**
* @return string
*/
public function getJobCommandName(): string
{
return $this->jobCommandName;
}
/**
* @return string
*/
public function getJobCommand(): string
{
return $this->jobCommand;
}
}
@@ -0,0 +1,35 @@
<?php
namespace App\Classes\Modules\Jobs\Processors;
use App\Classes\Modules\Jobs\Services\FetchesJobResult;
use Illuminate\Http\Request;
class FetchesJobResultProcessor
{
/** @var FetchesJobResult */
private $fetchesJobResult;
/**
* FetchesJobResultProcessor constructor.
* @param FetchesJobResult $fetchesJobResult
*/
public function __construct(FetchesJobResult $fetchesJobResult)
{
$this->fetchesJobResult = $fetchesJobResult;
}
public function execute(Request $request){
$res1 = $this->fetchesJobResult->execute(['job_id' => $request->route('job_id')]);
if(!$res1->result){
$res2 = $this->fetchesJobResult->execute(['request_signature' => $res1->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]);
return $res2;
}
return $res1;
}
}
@@ -10,18 +10,16 @@ class CreatesJobResult extends AbstractUpdateRecord
{
/**
* @param ListGenericJobObject $listGenericJobObject
* @param string $result
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(ListGenericJobObject $listGenericJobObject, string $result)
public function execute(ListGenericJobObject $listGenericJobObject)
{
$model = new JobResult();
$model->job_id = $listGenericJobObject->getJobId();
$model->result = $result;
$model->request_signature = $listGenericJobObject->getRequestSignature();
$model->result_signature = $listGenericJobObject->getResultSignature();
$model->url = $listGenericJobObject->getName();
$model->job_command_name = $listGenericJobObject->getJobCommandName();
$model->job_command = $listGenericJobObject->getJobCommand();
return $this->handler($model);
}
@@ -0,0 +1,33 @@
<?php
namespace App\Classes\Modules\Jobs\Services;
use App\Classes\General\Eloquent\AbstractListRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\JobResult;
class ListsJobResult extends AbstractListRecord
{
/** @var JobResult */
private $repository;
/**
* ListsJobResult constructor.
* @param JobResult $repository
*/
public function __construct(JobResult $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Classes\Modules\Jobs\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\Modules\Jobs\DataTransferObjects\UpdateJobResultObject;
use App\Models\JobResult;
class UpdatesJobResult extends AbstractUpdateRecord
{
/**
* @param JobResult $model
* @param UpdateJobResultObject $updateJobResultObject
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(JobResult $model, UpdateJobResultObject $updateJobResultObject) {
$model->result = $updateJobResultObject->getResult();
$model->result_signature = $updateJobResultObject->getResultSignature();
$model->job_command_name = $updateJobResultObject->getJobCommandName();
$model->job_command = $updateJobResultObject->getJobCommand();
return $this->handler($model);
}
}
@@ -9,19 +9,33 @@ use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Classes\Modules\Jobs\Services\CreatesJobResult;
class ListPackingListsJobLogic extends AbstractControllerLogic
{
/**
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'List Transaction Job',
'message' => 'You have successfully submit a job to list transactions'
'title' => 'Job Retrieving PackingLists',
'message' => 'You have successfully submit a job to retrieve a list of PackingLists'
];
}
/** @var CreatesJobResult */
private $createsJobResult;
/**
* ListPackingListsJobLogic constructor.
* @param CreatesJobResult $createsJobResult
*/
public function __construct(CreatesJobResult $createsJobResult)
{
$this->createsJobResult = $createsJobResult;
}
/**
* @param Request $request
* @return JsonResponse
@@ -32,13 +46,20 @@ class ListPackingListsJobLogic extends AbstractControllerLogic
$user = Auth::user();
$userInfo = (object) [
'email' => $user->email,
// 'email' => $user->email,
'type' => $user->type,
];
$userInfoJson = json_encode($userInfo);
$requestSignature = md5($userInfoJson . $request->fullUrl());
$listGenericJobObject = new ListGenericJobObject(
$request->fullUrl(),
$request->all(),
$requestSignature,
null,
$jobId,
$userInfo
);
@@ -48,6 +69,9 @@ class ListPackingListsJobLogic extends AbstractControllerLogic
$result = [];
$result['job_id'] = $jobId;
$this->createsJobResult->execute($listGenericJobObject);
return $this->response(['data' => $result]);
}
@@ -2,10 +2,13 @@
namespace App\Classes\Modules\PackingLists\Processors;
use App\Classes\Exceptions\JobResourceNotFoundException;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\Jobs\Services\CreatesJobResult;
use App\Classes\Modules\Jobs\Services\UpdatesJobResult;
use App\Classes\Modules\Jobs\Services\FetchesJobResult;
use App\Classes\General\Helper;
use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
use App\Classes\Modules\Jobs\DataTransferObjects\UpdateJobResultObject;
use App\Http\Resources\ListPackingListJobResource;
class ListPackingListsJobProcessor
@@ -14,24 +17,30 @@ class ListPackingListsJobProcessor
/** @var ListsPackingLists */
private $listsPackingLists;
/** @var CreatesJobResult */
private $createsJobResult;
/** @var FetchesJobResult */
private $fetchesJobResult;
/** @var UpdatesJobResult */
private $updatesJobResult;
/**
* ListPackingListsJobProcessor constructor.
* @param ListsPackingLists $listsPackingLists
* @param CreatesJobResult $createsJobResult
* @param FetchesJobResult $fetchesJobResult
* @param UpdatesJobResult $updatesJobResult
*/
public function __construct(ListsPackingLists $listsPackingLists, CreatesJobResult $createsJobResult)
public function __construct(ListsPackingLists $listsPackingLists, FetchesJobResult $fetchesJobResult, UpdatesJobResult $updatesJobResult)
{
$this->listsPackingLists = $listsPackingLists;
$this->createsJobResult = $createsJobResult;
$this->fetchesJobResult = $fetchesJobResult;
$this->updatesJobResult = $updatesJobResult;
}
/**
* @param ListGenericJobObject $listGenericJobObject
* @return null|object
* @return void
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\JobResourceNotFoundException
*/
public function execute(ListGenericJobObject $listGenericJobObject) {
@@ -39,9 +48,30 @@ class ListPackingListsJobProcessor
foreach ($query->items() as &$item) {
$item['userInfo'] = $listGenericJobObject->getUserInfo();
}
$result = Helper::collectionResponse(ListPackingListJobResource::collection($query));
$create = $this->createsJobResult->execute($listGenericJobObject, json_encode($result));
$resultCurrent = Helper::collectionResponse(ListPackingListJobResource::collection($query));
return $create;
$jobResultCurrent = $this->fetchesJobResult->execute(['job_id' => $listGenericJobObject->getJobId()]);
$resultCurrentJson = json_encode($resultCurrent);
$resultSignatureCurrent = md5($resultCurrentJson);
try{
$jobResultExisting = $this->fetchesJobResult->execute(['request_signature' => $jobResultCurrent->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]);
$resultSignatureExisting = $jobResultExisting->result_signature;
if($resultSignatureExisting != $resultSignatureCurrent){
$this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand());
}
} catch (JobResourceNotFoundException $exception){
$this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand());
}
}
private function updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $jobCommandName, $jobCommand){
$updateJobResultObject = new UpdateJobResultObject(
$resultCurrentJson,
$resultSignatureCurrent,
$jobCommandName,
$jobCommand
);
$create = $this->updatesJobResult->execute($jobResultCurrent, $updateJobResultObject);
}
}
@@ -16,7 +16,7 @@ class CreateJobResultsTable extends Migration
Schema::create('job_results', function (Blueprint $table) {
$table->id();
$table->string('job_id', 50);
$table->longText('result');
$table->longText('result')->nullable();
$table->timestamps();
// $table->foreign('job_id')->references('id')->on('jobs')->onDelete('cascade');
@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddNewColumn2ToJobResultsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('job_results', function (Blueprint $table) {
$table->string('request_signature')->after('job_id')->nullable();
$table->string('result_signature')->after('request_signature')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('job_results', function (Blueprint $table) {
$table->dropColumn('request_signature');
$table->dropColumn('result_signature');
});
}
}
@@ -126,7 +126,7 @@
errorHandler(error){
this.isPolling = false;
},
startPolling(jobId, maxAttempts = 3) {
startPolling(jobId, maxAttempts = 4) {
let attempts = 0;
const pollJobResult = () => {
if (this.isPolling) {
@@ -149,7 +149,7 @@
};
// pollJobResult(); // Initial call
this.pollingInterval = setInterval(pollJobResult, 10000);
this.pollingInterval = setInterval(pollJobResult, 15000);
},
stopPolling() {
clearInterval(this.pollingInterval);