微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在循环内优化 Laravel 作业

如何解决如何在循环内优化 Laravel 作业

作业(队列)中有一个函数。我调度那个队列。每个循环的内部。

public function autoConsignmentChargeCalculate($consignments,$user_id,$notify)
    {
        $i = 1;
        $total_consignments = $consignments->count();


        $jobs = [];
        foreach ($consignments as  $consignment) {

            $jobs[] = new CalculateSingleConsignment($consignment,$total_consignments,$i,$notify);
            $i++;
        }
        if (count($jobs) > 0) {
            Bus::chain($jobs)->onQueue('invoice')->dispatch();
        }
    }

job里面的函数

public function calculateConsignmentOneByOne($consignment,$current_iteration,$notify)
    {

        if ($consignment->finalize == 0) {

            $type = 'Income';
            $customer = Customer::find($consignment->customer_id);
            $delivery_run_id = $consignment->delivery_run_id;
            if ($consignment->consignment_type == 'pickup' || $consignment->consignment_type == 'return') {
                $delivery_address_id = $consignment->pickup_address;
            } else {
                $delivery_address_id = $consignment->delivery_address;
            }
            $customer_id = $consignment->customer_id;
            $rate_zone = $consignment->rate_zone_id;
            if ($rate_zone == null) {
                $address_to_rate_zone_mapping = getRateZoneByAddressMapping($consignment,$type);

                if ($address_to_rate_zone_mapping != false) {
                    $rate_zone = 0;
                    $rate_zone = $address_to_rate_zone_mapping;
                } else {
                    $rate_zone =   $this->getRateZone($delivery_run_id,$delivery_address_id,$type);
                }
            }
            if (!empty($consignment->invoice)) {
                if ($consignment->invoice->status === 3) {
                    $error = 'Related Invoice is Approved,Now you Can not modify charges';
                    chargeError('Consignment',$consignment->id,'invoice_approved',$error,$type);
                }
            }
            $productType = $consignment->product_type_id;
            if ($rate_zone === 'wrong_delivery_run') {
                $error = 'No Delivery Run is Assigned to this consignment';
                chargeError('Consignment','wrong_delivery_run',$type);
            } else if ($rate_zone === 'wrong_delivery_zone') {
                if ($consignment->consignment_type == 'pickup' || $consignment->consignment_type == 'return') {
                    $address_msg = 'Pickup address';
                } else {
                    $address_msg = 'Delivery address';
                }
                $error = 'Delivery Zone not found with current suburb and postcode given in ' . $address_msg;

                chargeError('Consignment','wrong_delivery_zone',$type);
            } else if (empty($productType)) {
                $error = 'Please Attach Product Type to Consignment';
                chargeError('Consignment','product_type_error',$type);
            } else if ($rate_zone === 'wrong_delivery_address') {
                $error = 'Delivery Address not Found,May be Deleted';
                chargeError('Consignment','wrong_delivery_address',$type);
            } else {
                $rate_charge = $this->getRateChargeByRateZoneAndCustomer($rate_zone,$type,$consignment,$customer);

                if ($rate_charge === 'rate_not_found') {
                    $error = 'Rate Card in Customer Charge with "' . RateZone::find($rate_zone)->name . '" Rate zone or Charge Type not found';
                    chargeError('Consignment','rate_not_found',$type);
                }
                if ($rate_charge === 'customer_not_found') {
                    $error = 'Customer Not Found,May be Deleted';
                    chargeError('Consignment','customer_not_found',$type);
                }
                if ($rate_charge === "invalid_carton_pallet") {
                    $error = 'No pallets or cartons given,check the consignment data has been loaded correctly.';
                    chargeError('Consignment','invalid_carton_pallet',$type);
                }
                if ($rate_charge === "invalid_invoice_value") {
                    $error = 'No invoice value given,'invalid_invoice_value',$type);
                }
                if ($rate_charge === "invalid_weight") {
                    $error = 'No Weight value given,'invalid_weight',$type);
                } else {


                    if ($type == 'Income') {
                        $rate_charge_array =   array('class' => null,'type' => $type,'description' => $this->chargeDescription,'income' => $rate_charge,'expense' => 0.00,'rate_zone_id' => $rate_zone,'customer_id' => $customer->id,'apply_fuel_levy' => $this->fuelLevy,'object_id' => $consignment->id,'model' => 'Consignment','automatic' => 1);
                    } else {
                        $rate_charge_array = array('class' => null,'income' => 0.00,'expense' => $rate_charge,'automatic' => 1);
                    }
                    if ($type == 'Income') {
                        $final_charges = $this->getAdhocChargeRate($consignment,'Consignment');
                    }

                    $final_charges[] = $rate_charge_array;
                    $final_charges = collect($final_charges);

                    Charge::where('object_id',$consignment->id)->where('automatic',1)->where('model','Consignment')->delete();
                    ChargeError::where('object_id',$consignment->id)->where('model','Consignment')->delete();

                    $this->storeAutoCalculatedConsignmentCharges($final_charges);
                    $this->calculateFuelLevyForConsignment($consignment->id);



                    //this will keep updating fuel levy with each consignment calculation
                    // if (Invoicetotal::where('invoice_id',$consignment->invoice_id)->where('name','Fuel Levy')->exists()) {
                    //     $income = 0;
                    //     $expense = 0;
                    //     $total = Invoicetotal::where('invoice_id','Fuel Levy')->first();
                    //     $income = (float)$total->income + (float)$consignment->charges()->sum('fuel_levy_value');
                    //     $expense += 0;
                    //     Invoicetotal::where('invoice_id','Fuel Levy')->update(['income' => $income,'expense' => $expense]);
                    //     $invoice = Invoice::find($consignment->invoice_id);


                    //     Invoice::where('id',$consignment->invoice_id)->update(['income' => $invoice->invoice_totals()->sum('income'),'expense' => $invoice->invoice_totals()->sum('expense')]);
                    // }
                    Invoice::find($consignment->invoice_id)->update(['sum_up' => 0]);
                }
            }



            $last_consignment = Consignment::select('id','invoice_id')->where('invoice_id',$consignment->invoice_id)->where('finalize',0)->orderBy('id','desc')->first();
            $invoice_id = $consignment->invoice_id;

            //if its last consignment to calculate and notify is true
            if ($notify && $total_consignments == $current_iteration) {
                Notification_Helper::sendNotification($user_id,'Invoice Calculation is Completed ',route('invoices.show',$consignment->invoice_id));
            }
            $upload_to_xero = 0;
            if (XeroCustomer::where('customer_id',$consignment->customer_id)->exists()) {
                if (XeroCustomer::where('customer_id',$consignment->customer_id)->first()->automatic_invoice_upload_xero == 1) {
                    $upload_to_xero = 1;
                }
            }

            if ($consignment->id == $last_consignment->id) {
                Invoice::find($invoice_id)->update(['calculation_complete' => 1]);
                $this->consignmentSumup($invoice_id);
            }


            //if its last consignment to calculate and has no charge error then
            //invoice will be uploaded to xero
            if ($consignment->id == $last_consignment->id) {
                //checking if error exists Related to current invoice
                $consignment_charge_exists = ChargeError::where('model','Consignment')->whereIn('object_id',function ($query) use ($invoice_id) {
                    $query->select('id')
                        ->from(with(new Consignment)->getTable())
                        ->where('invoice_id',$invoice_id);
                })->exists();

                $po_charge_exist = ChargeError::where('model','Purchase Order')->whereIn('object_id',function ($query) use ($invoice_id) {
                    $query->select('id')
                        ->from(with(new PurchaSEOrder)->getTable())
                        ->where('invoice_id',$invoice_id);
                })->exists();

                $so_charge_exist = ChargeError::where('model','Sale Order')->whereIn('object_id',function ($query) use ($invoice_id) {
                    $query->select('id')
                        ->from(with(new SaleOrder)->getTable())
                        ->where('invoice_id',$invoice_id);
                })->exists();

                $sp_charge_exist = ChargeError::where('model','Storage Period')->whereIn('object_id',function ($query) use ($invoice_id) {
                    $query->select('id')
                        ->from(with(new StoragePeriod)->getTable())
                        ->where('invoice_id',$invoice_id);
                })->exists();
                if (!$consignment_charge_exists && !$po_charge_exist && !$so_charge_exist && !$sp_charge_exist && $upload_to_xero == 1 && $this->consignmentSumup($invoice_id)) {
                    UploadInvoicetoXero::dispatch($consignment->invoice_id)->onQueue('invoice')->delay(Carbon::Now()->addMinutes(2));
                    // CustomerController::uploadAutoInvoicetoXero($consignment->invoice_id,$xeroCredential,new CustomerSettingService);
                    Invoice::find($consignment->invoice_id)->update(['sum_up' => 1]);
                } else {
                    Invoice::find($consignment->invoice_id)->update(['sum_up' => 1,'charge_error' => 1]);
                }
            } else {
                Invoice::find($consignment->invoice_id)->update(['sum_up' => 1,'charge_error' => 1]);
            }
        }
    }

现在的问题是这个函数内部有大约 20,30 个查询。我必须派遣这项工作大约 25000 次。当它达到 200 个工作岗位时。我的 aws DB cpu 利用率达到 100%。

现在我正在寻找可以增加数据库实例大小的最佳解决方案,但我认为这不是解决方案。

我可以在这里使用什么好的做法?

解决方法

SQL 在“相同”时间对大量行执行“相同”操作的速度非常快。

您似乎拥有的是执行 20-30 次小查询 25K 次的代码。

考虑进行 20-30 个(可能比这更多)查询,每个查询都作用于 25K 行。然后扔掉所有的排队,不用担心“同时”。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。