مجید
4 سال پیش توسط مجید مطرح شد
12 پاسخ

اطمینان از اجرای یک تابع به طور کامل

سلام، بنده نیاز دارم تابعی اجرا بشه و مقادیری رو در دیتابیس تغییر بده و مقادیری رو هم اضافه کنه،
مشکلی برای اجرا نیست و زمان زیادی هم طول نمیکشه ولی وقتی بلافاصله بعد از اجرا اگر back زده بشه اجرای تابع نصف کاره میمونه و نتیجه نهایی اشتباه میشه. چطور میتونم اجرای تابع رو کنترل کنم و از اجرای کاملش مطمئن بشم
ممنون میشم راهنمایی بفرمایید


ثبت پرسش جدید
محمدحسن یگانه
تخصص : Full-Stack Web Developer Freel...
@mhyeganeh 4 سال پیش مطرح شد
0

تعریفتون دقیقا از «روی هاست کار نمی‌کنه» چی هست؟ انتظار چه رفتاری دارید که خلافش انجام میشه؟

ضمنا مورد دوم اینکه برای استفاده از Transaction ها در لاراول یک روش دیگه هم وجود داره و اون هم با استفاده از دستورات زیر هست:

use Illuminate\Support\Facades\DB;

DB::beginTransaction();

با دستور بالا محدوده شروع Transaction رو معین مکنید. اگر در اواسط مشکلی بوجود اومد با دستور زیر rollback می‌کنید:

DB::rollBack();

و اگر تا آخرین خط کد رسید اون وقت بصورت دستی دستور commit رو به شکل زیر می‌دید تا همه کوئری ها با همدیگر اجرا شوند:

DB::commit();

یکبار با روش بالا تست کنید. شاید اوکی شد.


گرچه یک حدس دیگه هم دارم... مطمئن نیستم ولی تا جایی که میدونم وقتی یک ریکوئست ارسال شد و پردازشش در سمت سرور استارت خورد، عملا دیگه کاربر نمی تونه جلوش رو بگیره و stopش کنه و اون عملیات تا انتها انجام خواهند شد. حتی اگر در طول این مدت کاربر back زده باشه. اتفاقی که در این صورت می افته این هست که فقط response به کاربر نمی رسه ولی اصل اتفاق که در سمت سرور هست تا انتها انجام میشه. شاید به همین خاطر هست که Transaction با موفقیت commit میشه. چون هیچ مانعی براش بوجود نمیاد که خواسته باشه rollback کنه.

هر چقدر فکر میکنم مثالی هم خاطرم نمیاد که در سایتی کاربر با back زدن بتونه جلوی اجرای عملیات رو در سمت سرور بگیره. فقط با اینکار ارتباط خودش رو قطع می کنه و response بهش نمی رسه. به همین خاطر هم هست که در کارهای حساس مثل پرداخت و آزمون و ثبت نام و ... میگن به هیچ وجه از کلید back استفاده نکنید.

@ali.bayat آقای بیات خوشحال میشم نظرتون رو بشنوم. به نظرتون حدسم درسته و درست متوجه این قضیه شدم؟


علی بیات
تخصص : توسعه دهنده ارشد وب
@ali.bayat 4 سال پیش مطرح شد
3

این پروسه شامل ۲ تا کوئری میشه
شما برای اینکه اطمینان پیدا کنی که هر ۲ تا اجرا میشه باید از سیستم Transaction استفاده کنی
به این ترتیب اگر یکی از کوئری هات Fail هم بشه
سایر کوئری ها هم rollback میشند


DB::transaction(function(){
    Model1::insert([]);
    Model2::update([]);
});

به عبارت دیگه یا همش با هم اجرا میشه یا هیچکدوم اجرا نمیشه


مجید
تخصص : برنامه نویس
@majeeddehghan 4 سال پیش مطرح شد
0

@ali.bayat ممنون از راهنماییتون


مجید
تخصص : برنامه نویس
@majeeddehghan 4 سال پیش مطرح شد
0

@ali.bayat از سیستم transaction استفاده کردم اما بازم هنگام لود شدن صفحه اگر back زده بشه کامل اجرا نمیشه
راه دیگه ای وجود نداره؟
ممنون میشم راهنمایی بفرمایید
@milad @mhyeganeh @hesammousavi @saman1111 @Rp76 @nimageneral


مجید
تخصص : برنامه نویس
@majeeddehghan 4 سال پیش آپدیت شد
0

ممنون میشم راهنمایی کنید


علی بیات
تخصص : توسعه دهنده ارشد وب
@ali.bayat 4 سال پیش آپدیت شد
0

هنگام لود شدن صفحه اگر back زده بشه

با این کار شما فرصت اجرای کامل این قطعه کد رو میگیری
و چون داری از transaction استفاده میکنی قاعدتا همه تغییرات rollback میشه


یه نکته جانبی:
کدت رو بررسی کردم. حداقل 5،6 جا foreach داری که داخلش کوئری ساخته و اجرا میشه
این کار اصلا بهینه نیست
اولا باعث میشه زمان اجرا و لود صفحه بالا بره
دوما برای یه پروژه کوچیک این زمان شاید قابل تحمل باشه اما وقتی سرور زیر بار باشه، اصلا خوب نیست

قبلش یه کوئری لاگ بگیر
ببین چند تا کوئری داره برای این یه تیکه کد اجرا میشه


مجید
تخصص : برنامه نویس
@majeeddehghan 4 سال پیش مطرح شد
0

@ali.bayat
تغییرات rollback نمیشه ؟
در حین لود back میزنم اما rollback نمیشه باید چیکار کنم ؟


مجید
تخصص : برنامه نویس
@majeeddehghan 4 سال پیش مطرح شد
0

تست کردم روی لوکال جواب میده و مشکلی نداره اما روی هاست کارنمیکنه ؟
همچین چیزی ممکنه ؟


محمدحسن یگانه
تخصص : Full-Stack Web Developer Freel...
@mhyeganeh 4 سال پیش مطرح شد
0

اول اینکه کدتون یکسری ایرادهای نسبتا جدی داره. دنبال بهینه سازیش باشید در اولین فرصت.

دوما Transaction ها هم می تونه یک راهکار خوب باشه و معنی نداره در هیچ زمانی فقط بخشیش انجام شده باشه. معناش کلا این هست یا همه اش با هم و یا هیچ کدوم. اگر این اتفاق نمی افته در پیاده سازیش اشتباه کردید.

و اما اگر اجرای فرایندتون زمان بر هست، یک پیشنهاد دیگه این هست که از Queue و job در لاراول استفاده کنید. به این شکل که با کلیک بروی لینک مورد نظر صرفا job ساخته میشه و به صف اضافه بشه. و در همین جا پاسخ رو برگردونید. بدلیل زمان کمی که برای این بخش از کار نیاز هست معمولا فرصت اینکه کاربر بخواد back بزنه وجود نداره اصلا و خیلی سریع اتفاق می افته. در صفحه بعد به کاربر یک پیغام نمایش داده میشه مثل «در حال پردازش...»

وقتی job به صف اضافه شد، پشت صحنه worker ها به سراغش میرن و عملیات رو تکمیل می‌کنند. اگر نیاز بود می‌تونید با ajax هر چند ثانیه یکبار درخواست بزنید که هر وقت عملیات تکمیل شده بود، به کاربر اطلاع بدید. یا از وب سوکت استفاده کنید تا ارتباط دو طرفه برقرار بشه.


مجید
تخصص : برنامه نویس
@majeeddehghan 4 سال پیش مطرح شد
0

@mhyeganeh حتما بهینه سازی میکنم فقط اینکه
روی لوکال مشکلی نداره پس نمیتونه پیاده سازیش مشکل داشته باشه روی هاست مشکل پیدا میکنه و کار نمیکنه
نحوه پیاده سازی هم داخل کد بالا مشخص هست
راهی نداره همین transaction کارکنه ؟


مجید
تخصص : برنامه نویس
@majeeddehghan 4 سال پیش مطرح شد
0

روی لوکال بدون استفاده از transaction هم درست کار میکنه و مشکلی نداره
روی هاست داخل تابع از کد زیر استفاده میکنم اما با این که اجرای تابع نیمه کاره انجام میشه متد rollback انجام نمیشه
اروری هم نمیده
ممنون میشم اگه راهنمایی کنید

DB::transaction(function (){
            foreach ($tests1 as $test) {
                $t1 = Model1::where('id',$test->id)->first();
                $data['value'] = 100;
                $t->update($data);
            }
            foreach ($tests2 as $test) {
                $t2 = Model2::where('id',$test->id)->first();
                $data['value'] = 100;
                $t2->update($data);
            }

            });

محمدحسن یگانه
تخصص : Full-Stack Web Developer Freel...
@mhyeganeh 4 سال پیش مطرح شد
0

تعریفتون دقیقا از «روی هاست کار نمی‌کنه» چی هست؟ انتظار چه رفتاری دارید که خلافش انجام میشه؟

ضمنا مورد دوم اینکه برای استفاده از Transaction ها در لاراول یک روش دیگه هم وجود داره و اون هم با استفاده از دستورات زیر هست:

use Illuminate\Support\Facades\DB;

DB::beginTransaction();

با دستور بالا محدوده شروع Transaction رو معین مکنید. اگر در اواسط مشکلی بوجود اومد با دستور زیر rollback می‌کنید:

DB::rollBack();

و اگر تا آخرین خط کد رسید اون وقت بصورت دستی دستور commit رو به شکل زیر می‌دید تا همه کوئری ها با همدیگر اجرا شوند:

DB::commit();

یکبار با روش بالا تست کنید. شاید اوکی شد.


گرچه یک حدس دیگه هم دارم... مطمئن نیستم ولی تا جایی که میدونم وقتی یک ریکوئست ارسال شد و پردازشش در سمت سرور استارت خورد، عملا دیگه کاربر نمی تونه جلوش رو بگیره و stopش کنه و اون عملیات تا انتها انجام خواهند شد. حتی اگر در طول این مدت کاربر back زده باشه. اتفاقی که در این صورت می افته این هست که فقط response به کاربر نمی رسه ولی اصل اتفاق که در سمت سرور هست تا انتها انجام میشه. شاید به همین خاطر هست که Transaction با موفقیت commit میشه. چون هیچ مانعی براش بوجود نمیاد که خواسته باشه rollback کنه.

هر چقدر فکر میکنم مثالی هم خاطرم نمیاد که در سایتی کاربر با back زدن بتونه جلوی اجرای عملیات رو در سمت سرور بگیره. فقط با اینکار ارتباط خودش رو قطع می کنه و response بهش نمی رسه. به همین خاطر هم هست که در کارهای حساس مثل پرداخت و آزمون و ثبت نام و ... میگن به هیچ وجه از کلید back استفاده نکنید.

@ali.bayat آقای بیات خوشحال میشم نظرتون رو بشنوم. به نظرتون حدسم درسته و درست متوجه این قضیه شدم؟


علی بیات
تخصص : توسعه دهنده ارشد وب
@ali.bayat 4 سال پیش مطرح شد
1

@mhyeganeh

به نظر من هم پروسه ای که سمت سرور استارت میخوره، معمولا ادامه پیدا میکنه
نهایتا کاربره که با اجرای یه درخواست دیگه و یا استفاده از back خودش باعث میشه response رو نبینه.

صحبتتون منطقی به نظر میرسه


برای ارسال پاسخ لازم است وارد شده یا ثبت‌نام کنید

ورود یا ثبت‌نام