mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 04:23:55 +00:00
Proof of concept - Vue Polling a workaround for AWS API Gateway limitation
This commit is contained in:
@@ -16,6 +16,8 @@ class ListBookingsJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $timeout = 900;
|
||||
|
||||
/** @var ListGenericJobObject */
|
||||
private $listGenericJobObject;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ class ListDocumentsJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $timeout = 900;
|
||||
|
||||
/** @var ListGenericJobObject */
|
||||
private $listGenericJobObject;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ class ListTransactionsJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $timeout = 900;
|
||||
|
||||
/** @var ListGenericJobObject */
|
||||
private $listGenericJobObject;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Classes\Modules\Jobs\Processors;
|
||||
|
||||
use App\Classes\Exceptions\JobResourceNotFoundException;
|
||||
use App\Classes\Modules\Jobs\Services\FetchesJobResult;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -32,12 +33,13 @@ class FetchesJobResultProcessor
|
||||
public function execute(Request $request){
|
||||
|
||||
$res1 = $this->fetchesJobResult->execute(['job_id' => $request->route('job_id')]);
|
||||
if($request->route('is_last')){
|
||||
$res2 = $this->fetchesJobResult->execute(['request_signature' => $res1->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]);
|
||||
return $res2;
|
||||
}
|
||||
|
||||
if(!$res1->result){
|
||||
Log::info('Job id: '.$request->route('job_id'));
|
||||
$res2 = $this->fetchesJobResult->execute(['request_signature' => $res1->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]);
|
||||
Log::info('Job id: '.$res2->id." , request_signature: ".$res2->request_signature);
|
||||
return $res2;
|
||||
throw new JobResourceNotFoundException('Unable to find any job based on the criteria provided');
|
||||
}
|
||||
|
||||
return $res1;
|
||||
|
||||
@@ -44,9 +44,9 @@ class UpdateJobResultProcessor
|
||||
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){
|
||||
//if($resultSignatureExisting != $resultSignatureCurrent){
|
||||
$this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand());
|
||||
}
|
||||
//}
|
||||
} catch (JobResourceNotFoundException $exception){
|
||||
$this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand());
|
||||
}
|
||||
|
||||
+13
-13
@@ -90,34 +90,34 @@
|
||||
<div class="row no-margin">
|
||||
<div class="col bg-white padding-25">
|
||||
<div class="row tabsContainer tabContent m-l-0 m-r-0" tab-name="invoice" v-if="isActiveTab('invoice') || showTabContent('invoice')">
|
||||
<list-polling-component key="2" section="invoiceSection" :endpoint="route('api.document.list.job')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['INVOICE']}">
|
||||
<list-component key="2" section="invoiceSection" :endpoint="route('api.document.list')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['INVOICE']}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<billing-document-component :data="data"></billing-document-component>
|
||||
</template>
|
||||
</list-polling-component>
|
||||
</div>
|
||||
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="purchase-order" v-if="isActiveTab('purchase-order') || showTabContent('purchase-order')">
|
||||
<list-polling-component key="2" section="purchaseOrderSection" :endpoint="route('api.document.list.job')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['PURCHASE_ORDER']}">
|
||||
</list-component>
|
||||
</div>
|
||||
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="purchase-order" v-if="isActiveTab('purchase-order') || showTabContent('purchase-order')">
|
||||
<list-component key="2" section="purchaseOrderSection" :endpoint="route('api.document.list')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['PURCHASE_ORDER']}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<billing-document-component :data="data"></billing-document-component>
|
||||
</template>
|
||||
</list-polling-component>
|
||||
</div>
|
||||
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="delivery-order" v-if="isActiveTab('delivery-order') || showTabContent('delivery-order')">
|
||||
<list-polling-component key="2" section="deliveryOrderSection" :endpoint="route('api.document.list.job')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['DELIVER_ORDER']}">
|
||||
</list-component>
|
||||
</div>
|
||||
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="delivery-order" v-if="isActiveTab('delivery-order') || showTabContent('delivery-order')">
|
||||
<list-component key="2" section="deliveryOrderSection" :endpoint="route('api.document.list')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['DELIVER_ORDER']}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<billing-document-component :data="data"></billing-document-component>
|
||||
</template>
|
||||
</list-polling-component>
|
||||
</list-component>
|
||||
</div>
|
||||
<div class="row tabsContainer tabContent m-l-0 m-r-0 hide" tab-name="supplier-delivery-order" v-if="isActiveTab('supplier-delivery-order') || showTabContent('supplier-delivery-order')">
|
||||
<list-polling-component key="2" section="SupplierDeliveryOrderSection" :endpoint="route('api.document.list.job')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['SUPPLIER_DELIVER_ORDER']}">
|
||||
<list-component key="2" section="SupplierDeliveryOrderSection" :endpoint="route('api.document.list')" :options="{'per_page': 30, 'with_owner': true, 'document_type_in': ['SUPPLIER_DELIVER_ORDER']}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<billing-document-component :data="data"></billing-document-component>
|
||||
</template>
|
||||
</list-polling-component>
|
||||
</div>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+136
File diff suppressed because one or more lines are too long
+4
-4
@@ -118,16 +118,16 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<!-- CIEF TODO: For easy revert to old code -->
|
||||
<!-- <list-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id}">
|
||||
<list-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<supplier-pending-order-component :data="data" v-on:input="updateOrder($event)"></supplier-pending-order-component>
|
||||
</template>
|
||||
</list-component> -->
|
||||
<list-polling-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list.job')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id}">
|
||||
</list-component>
|
||||
<!-- <list-polling-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list.job')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<supplier-pending-order-component :data="data" v-on:input="updateOrder($event)"></supplier-pending-order-component>
|
||||
</template>
|
||||
</list-polling-component>
|
||||
</list-polling-component> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import requestV2 from '../../../general/mixins/aws/requestV2'
|
||||
export default {
|
||||
props: {
|
||||
section:{
|
||||
@@ -75,6 +76,7 @@
|
||||
filters: this.options,
|
||||
pollingInterval: null,
|
||||
isPolling: false,
|
||||
isFetchingResult: false,
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
@@ -124,50 +126,58 @@
|
||||
total: result.meta.total
|
||||
};
|
||||
|
||||
console.log('ListPolling:', JSON.stringify(result.meta));
|
||||
this.stopPolling();
|
||||
this.$store.dispatch('completeList', {'name': this.section, 'data': result.data});
|
||||
this.$refs.pagination.makePagination(result.meta, result.links);
|
||||
this.isLoading = false;
|
||||
},
|
||||
errorHandler(error){
|
||||
// console.log('ListPolling error:', JSON.stringify(error));
|
||||
this.isFetchingResult = false;
|
||||
this.isPolling = false;
|
||||
// this.isLoading = false;
|
||||
},
|
||||
startPolling(jobId, maxAttempts = 3) {
|
||||
startPolling(jobId, maxAttempts = 8) {
|
||||
let attempts = 0;
|
||||
let interval = 10000; // Initial interval
|
||||
|
||||
const resetPollingInterval = (customInterval) => {
|
||||
this.pollingInterval = setInterval(pollJobResult, customInterval);
|
||||
};
|
||||
|
||||
const pollJobResult = () => {
|
||||
if (this.isPolling) {
|
||||
if (this.isPolling || this.isFetchingResult) {
|
||||
return;
|
||||
}
|
||||
this.isPolling = true;
|
||||
|
||||
attempts++;
|
||||
if(attempts === 1){
|
||||
this.stopPolling();
|
||||
resetPollingInterval(5000);
|
||||
}
|
||||
|
||||
if (attempts > maxAttempts) {
|
||||
clearInterval(this.pollingInterval);
|
||||
this.pollingInterval = null;
|
||||
this.isPolling = false;
|
||||
this.stopPolling();
|
||||
this.isLoading = false;
|
||||
console.log(`Reached maximum attempts (${maxAttempts}). Polling stopped.`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.fetchJobResult(jobId);
|
||||
if(attempts === maxAttempts){
|
||||
this.fetchJobResult(jobId, true);
|
||||
}
|
||||
else{
|
||||
this.fetchJobResult(jobId);
|
||||
}
|
||||
};
|
||||
|
||||
// Initial call
|
||||
// pollJobResult();
|
||||
|
||||
// Set up polling interval
|
||||
this.pollingInterval = setInterval(pollJobResult, 10000);
|
||||
|
||||
// pollJobResult(); // Initial call
|
||||
this.pollingInterval = setInterval(pollJobResult, interval);
|
||||
},
|
||||
stopPolling() {
|
||||
clearInterval(this.pollingInterval);
|
||||
this.pollingInterval = null;
|
||||
this.isPolling = false;
|
||||
this.isFetchingResult = false;
|
||||
},
|
||||
submitJob(url){
|
||||
try {
|
||||
@@ -181,24 +191,23 @@
|
||||
}
|
||||
});
|
||||
})
|
||||
// this.job.progress = response.data.progress;
|
||||
// this.job.completed = response.data.completed;
|
||||
|
||||
// if (this.job.completed) {
|
||||
// this.stopPolling();
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error('Error submitJob', error);
|
||||
}
|
||||
},
|
||||
fetchJobResult(jobId) {
|
||||
fetchJobResult(jobId, isLastAttempt = false) {
|
||||
this.isFetchingResult = true;
|
||||
try {
|
||||
let anotherEndpoint = route('api.job.fetch', jobId);
|
||||
this.submit(anotherEndpoint, 'get', this.section, false, false); //cief todo: Uncaught (in promise) null
|
||||
if(isLastAttempt){
|
||||
anotherEndpoint = route('api.job.fetch.last.attempt', jobId, isLastAttempt);
|
||||
}
|
||||
this.poll(anotherEndpoint, 'get', this.section, false, false); //cief todo: Uncaught (in promise) null
|
||||
} catch (error) {
|
||||
console.error('Error fetchJobResult', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [requestV2]
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@extends('layouts.base_portal')
|
||||
@section('inner_content')
|
||||
<div class="row" v-if="$store.getters.isAdmin">
|
||||
<div class="col p-t-15 p-b-15">
|
||||
<billing-component></billing-component>
|
||||
<admin-payments-billing-section-polling-component></admin-payments-billing-section-polling-component>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -4,4 +4,5 @@ use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::group(['prefix' => 'job', 'as' => 'job.', 'namespace' => 'Jobs'], function () {
|
||||
Route::get('/fetch/{job_id}', 'FetchJobResultController@fetch')->name('fetch');
|
||||
Route::get('/fetch/{job_id}/{is_last}', 'FetchJobResultController@fetch')->name('fetch.last.attempt');
|
||||
});
|
||||
|
||||
+9
-3
@@ -92,6 +92,12 @@ Route::get('/billings', function () {
|
||||
return view('pages.billings');
|
||||
})->name('billings');
|
||||
|
||||
/* Vue Polling Experiment - Starts */
|
||||
Route::get('/billings-experiment', function () {
|
||||
return view('pages.billings_experiment');
|
||||
})->name('billings.experiment');
|
||||
/* Vue Polling Experiment - Ends */
|
||||
|
||||
Route::get('/currency_orders', function () {
|
||||
return view('pages.currency_orders');
|
||||
})->name('currency_orders');
|
||||
@@ -813,13 +819,13 @@ Route::get('/invoice/{marking}/{started_at}/{ended_at}/fix', function($marking,
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'asc')
|
||||
->first();
|
||||
|
||||
|
||||
// get the first bill_no
|
||||
$firstBillNo = $firstInvoice->bill_no;
|
||||
if (strpos($firstBillNo, '-deleted') !== false) {
|
||||
$firstBillNo = substr($firstBillNo, 0, strpos($firstBillNo, '-deleted'));
|
||||
}
|
||||
|
||||
|
||||
// update currentInvoice bill_no to '-deleted-'
|
||||
$currentInvoice = $booking->transactions()->where('type', TransactionType::INVOICE)->first();
|
||||
$currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . Str::random(10);
|
||||
@@ -842,4 +848,4 @@ Route::get('/invoice/{marking}/{started_at}/{ended_at}/fix', function($marking,
|
||||
}
|
||||
}
|
||||
);
|
||||
})->name('invoice.fix.byCustomerMarking');
|
||||
})->name('invoice.fix.byCustomerMarking');
|
||||
|
||||
Reference in New Issue
Block a user