Nếu bạn đã đi làm vài năm, bạn sẽ thấy “Scheduler” không phải chuyện viết vài dòng dailyAt(). Nó là bài toán reliability + performance + observability. Sai một ly là: trùng charge, spam notify, kẹt DB lúc 9h, hoặc “đêm qua không chạy mà không ai biết”.
Bài này chia sẻ theo góc nhìn hệ thống lớn: ra quyết định kỹ thuật khi số job tăng nhanh, dữ liệu lớn, nhiều worker, CI/CD liên tục, thậm chí realtime.
1. Nguyên tắc số 1: Scheduler phải “nhẹ” — việc nặng đẩy qua queue
Tư duy: Scheduler là “orchestrator”, không phải “executor”.
Scheduler chỉ làm 2 việc:
- Quyết định “đúng giờ thì trigger cái gì”
- Dispatch nhanh, ghi dấu vết (batch metadata)
Việc nặng (DB scan, gọi API, gửi notify hàng loạt, reconcile, billing…) → chạy trong queued jobs + nhiều worker.
Trade-off:
- ✅ Ưu: Scale bằng worker, retry/backoff chuẩn, tách tải khỏi scheduler
- ⚠️ Nhược: Job có thể chạy trễ → phải thiết kế theo “batch time” (xem phần 4)
Sai lầm thường gặp: Nhét logic nặng vào scheduler (closure/command) rồi “đỡ nghẽn” bằng cách tăng CPU. Đến lúc 100 lịch/ngày thì scheduler thành single-point bottleneck.
Ví dụ:
<?php
// routes/console.php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schedule;
// ❌ SAI: Logic nặng trực tiếp trong scheduler
Schedule::call(function () {
DB::table('recent_users')->chunk(100, function ($users) {
foreach ($users as $user) {
// Process payment, send email, update DB...
// Nếu có 1000 users, scheduler sẽ bị block rất lâu
}
});
})->dailyAt('09:00');
// ✅ ĐÚNG: Scheduler chỉ dispatch job
Schedule::job(new ProcessRecentUsersJob)
->dailyAt('09:00');
Scheduler chỉ trigger đúng giờ, không bao giờ chạy logic business trực tiếp. Worker sẽ xử lý job trong queue.
2. “Đúng một lần” theo nghĩa business > “đúng một lần” theo nghĩa kỹ thuật
Ở hệ thống lớn, “at least once” là mặc định. Scheduler/queue/worker/retry/deploy đều có thể làm job chạy lại.
Best practice: Thiết kế job theo idempotent:
- Chạy 2 lần vẫn ra kết quả đúng
- Side-effect (charge/send/update) phải có khóa logic hoặc unique key
Dùng lock ở đúng tầng:
- Tầng scheduler: Chống chồng / chạy một server (khi HA)
- Tầng job/business: Lock theo entity/time-window (mới là thứ bảo vệ cuối)
Trade-off:
- Lock nhiều quá → Giảm throughput, dễ nghẽn nếu lock sai granularity
- Lock ít quá → Trùng dữ liệu/side-effect
Sai lầm thường gặp: Tin tuyệt đối vào “chống chồng” của scheduler rồi bỏ qua idempotency. Một ngày deploy “đúng lúc”, bạn sẽ hiểu.
Ví dụ:
Job có idempotency key dựa trên entity_id + batch_time. Concept này áp dụng cho mọi job có side-effect quan trọng. Trong scheduler, bạn chỉ dispatch job với metadata:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::job(new ProcessOrdersJob)
->dailyAt('09:00');
Job sẽ tự implement idempotency check trong handle() method để đảm bảo không xử lý trùng.
3. Khi nào dùng runInBackground() và khi nào “bắt buộc” dùng queue?
Tôi coi runInBackground() là giải pháp tactical, không phải chiến lược lâu dài.
Dùng runInBackground() khi:
- Task là command/exec tương đối ngắn
- Không cần scale theo tải
- Bạn chỉ cần tránh scheduler bị giữ process quá lâu
Bắt buộc đưa qua queue khi:
- Task có thể chạy vài chục giây/phút
- Task có thể “nở” theo dữ liệu (data grows)
- Task có side-effect quan trọng (payment/notify hàng loạt)
- Cần retry/backoff, rate-limit, phân ưu tiên
Sai lầm thường gặp: “Task đang lâu → thêm runInBackground()” và coi như xong. Thực tế bạn chỉ chuyển nghẽn từ scheduler sang CPU/DB/connections của cùng máy.
Ví dụ:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
// ✅ Dùng runInBackground cho command nhẹ, không cần scale
Schedule::command('cache:clear')
->hourly()
->runInBackground();
Schedule::command('emails:send')
->dailyAt('02:00')
->runInBackground();
// ✅ Bắt buộc dùng queue cho job có side-effect quan trọng
Schedule::job(new SendOrderConfirmationJob)
->dailyAt('09:00'); // Không có runInBackground, vì đã là queued job
Chỉ có 2 loại command dùng runInBackground():
- Maintenance commands (cleanup, cache) — không ảnh hưởng business
- Monitoring commands — cần chạy nhanh, không cần retry
Tất cả job business đều qua queue để có retry/backoff/scale.
4. Bài toán lớn nhất của hệ queue: Job chạy trễ → lệch cửa sổ dữ liệu
Đây là điểm phân biệt hệ “chạy được” và hệ “chạy đúng”.
Vấn đề:
- Scheduler trigger 09:00, worker chạy 09:04
- Nếu job query theo
now()lúc 09:04, bạn vừa:- Miss dữ liệu 09:00–09:04 (tùy window)
- Hoặc duplicate với batch trước
Giải pháp: Scheduler đóng dấu batch time ngay lúc dispatch (tôi hay gọi scheduledAt/batchAt). Job luôn dùng scheduledAt để:
- Tính window dữ liệu
- Log/audit theo batch
- Tạo idempotency key
Trade-off:
- Tốn thêm metadata, thêm “kỷ luật” trong code
- Đổi lại: Batch chạy trễ vẫn đúng cửa sổ, dễ đối soát, dễ replay theo batch
Ví dụ — Pattern batch timestamp:
Concept: Scheduler đóng dấu batch time ngay lúc dispatch. Job nhận batch time và dùng để tính time window, không dùng now().
Sử dụng trong Laravel 12:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::job(new ProcessOrdersJob)
->dailyAt('09:00');
Job sẽ nhận scheduledAt từ scheduler event và dùng để query đúng time window.
Ví dụ với sub-minute scheduling trong Laravel 12:
Theo Laravel 12.x Sub-Minute Scheduled Tasks:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
// Laravel 12 hỗ trợ sub-minute scheduling
Schedule::call(function () {
// Process tasks every 30 seconds
})->everyThirtySeconds();
Lợi ích:
- Job chạy trễ 3 phút vẫn query đúng cửa sổ 09:00–09:01
- Dễ đối soát: “Batch 09:00 đã xử lý bao nhiêu records?”
- Dễ replay: “Chạy lại batch 09:00” → chỉ cần tạo job với
jobCreatedAt = 09:00
5. Tách “workload shape”: Phân queue theo ưu tiên, tránh job “rác” ăn tài nguyên job “sống còn”
Một hệ thống lớn sẽ có job kiểu:
- Critical: Billing, payment, cancel, inventory, security
- Default: Vận hành
- Low: Marketing, remind, digest
Best practice: Tách queue theo priority, scale worker theo queue. Đặt rule: Job low không bao giờ được làm chậm job critical.
Trade-off:
- Nhiều queue → Config vận hành phức tạp hơn (supervisor/horizon)
- Nhưng nếu không tách, bạn sẽ gặp kiểu “19h campaign bắn notify” làm nghẽn payment
Lưu ý: Trong scheduler, bạn có thể chỉ định queue khi schedule job:
Theo Laravel 12.x Scheduling Queued Jobs, method job() nhận queue name làm tham số thứ 2:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::job(new SendOrderConfirmationJob, 'critical')
->dailyAt('09:00');
Hoặc nếu job class đã có property $queue, scheduler sẽ tự động dùng queue đó.
6. “Thundering herd” lúc tròn giờ: Kẻ thù của DB và API
Hệ thống lớn rất hay bị “dồn lịch” vào 00:00, 09:00, 12:00, 19:00…
Best practice:
- Stagger: Dàn đều theo phút/giây
- Nếu bắt buộc tròn giờ: Chia nhỏ thành nhiều job chunk, có rate-limit/backoff
- Không quét toàn bảng: Dùng cursor/chunk theo index, watermark theo batch
Sai lầm thường gặp: Một job “tổng hợp cuối ngày” chạy 00:00 quét cả bảng 50 triệu dòng. Đêm đó DB chết, sáng không ai biết vì không có alert.
Ví dụ — Stagger pattern trong scheduler:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
// Dàn đều theo phút để tránh thundering herd
$times = ['9:03', '10:03', '11:03', '12:03', '13:03', '14:03', '15:03', '16:03', '17:03', '18:03', '19:03', '20:03', '21:03'];
foreach ($times as $time) {
Schedule::job(new ProcessHourlyTaskJob)
->at($time);
}
7. Observability là bắt buộc: “Không ai biết scheduler fail” = thất bại hệ thống
Scheduler fail nguy hiểm vì nó âm thầm.
Best practice:
- Log theo batch (scheduledAt, job name, duration, result)
- Có alert khi fail (hook/event/ping tùy hệ)
- Có “schedule inventory”: Định kỳ audit lịch chạy (ít nhất kiểm lịch sau deploy)
Trade-off:
- Thêm log/metrics → Tốn công + tốn storage
- Nhưng thiếu nó thì khi sự cố xảy ra, bạn mất nhiều giờ “đào mộ”
Ví dụ — Scheduler hooks trong Laravel 12:
Theo Laravel 12.x Task Hooks:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('emails:send')
->daily()
->before(function () {
// The task is about to execute...
})
->after(function () {
// The task has executed...
})
->onSuccess(function () {
// The task succeeded...
})
->onFailure(function () {
// The task failed...
});
Scheduler setup:
# Cron entry
* * * * * cd /path-to-app && php artisan schedule:run >> /dev/null 2>&1
Kiểm tra lịch chạy:
# Laravel 12: Xem tất cả scheduled tasks
php artisan schedule:list
8. CI/CD & Deploy: Đừng để deploy tạo ra double-run / half-run
Ở môi trường deploy liên tục, scheduler/worker cần “graceful”:
Best practice:
- Tránh chạy song song 2 version job logic cho cùng một batch
- Worker restart có kiểm soát; job quan trọng có idempotency key để chịu được retry/duplicate
- Nếu hệ HA nhiều scheduler node: Phải có chiến lược “one server” + shared lock store
Sai lầm thường gặp: Deploy xong “mọi thứ xanh”, nhưng lịch 09:00 bị chạy 2 lần vì 2 scheduler node cùng tick.
Ví dụ — Laravel 12 onOneServer():
Theo Laravel 12.x Running Tasks on One Server:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
// Nếu có nhiều scheduler server, dùng onOneServer() để chạy chỉ trên 1 server
Schedule::command('emails:send')
->daily()
->onOneServer(); // Chỉ chạy trên 1 server, dùng cache để lock
Lưu ý: Job vẫn phải idempotent vì:
- Retry khi fail
- Deploy có thể làm job chạy lại
- Worker restart có thể làm job chạy lại
9. Tổ chức code: Khi Kernel.php “phình to”
Khi số lượng lịch tăng, Kernel.php sẽ rất dài (có thể lên 300+ lines).
Best practice — Laravel 12: Tách helper functions theo domain để dễ maintain:
Theo Laravel 12.x Defining Schedules, bạn có thể định nghĩa trong routes/console.php và tách thành helper functions:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
// Tách theo domain để dễ maintain
schedulePaymentTasks();
scheduleNotificationTasks();
scheduleCleanupTasks();
function schedulePaymentTasks(): void
{
Schedule::command('payments:process')
->dailyAt('09:00');
Schedule::command('payments:retry')
->dailyAt('14:00');
}
function scheduleNotificationTasks(): void
{
Schedule::command('notifications:send')
->hourly();
Schedule::command('notifications:digest')
->dailyAt('20:00');
}
function scheduleCleanupTasks(): void
{
Schedule::command('cache:clear')
->hourly()
->runInBackground();
}
Hoặc dùng withSchedule trong bootstrap/app.php và tách thành methods:
<?php
// bootstrap/app.php
use Illuminate\Console\Scheduling\Schedule;
->withSchedule(function (Schedule $schedule) {
schedulePaymentTasks($schedule);
scheduleNotificationTasks($schedule);
scheduleCleanupTasks($schedule);
});
function schedulePaymentTasks(Schedule $schedule): void
{
$schedule->command('payments:process')->dailyAt('09:00');
$schedule->command('payments:retry')->dailyAt('14:00');
}
Lợi ích:
- Dễ review: Mỗi function = 1 domain
- Dễ test: Có thể test từng domain riêng
- Dễ ownership: Team có thể own từng domain
- Tránh Kernel.php phình to: Code nằm trong
routes/console.phphoặc helper functions
Schedule Groups — Laravel 12:
Theo Laravel 12.x Schedule Groups, bạn có thể nhóm các tasks có cùng cấu hình để tránh lặp lại code:
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
// ❌ SAI: Lặp lại cấu hình cho từng task
Schedule::command('emails:send')
->daily()
->onOneServer()
->timezone('America/New_York');
Schedule::command('emails:prune')
->daily()
->onOneServer()
->timezone('America/New_York');
// ✅ ĐÚNG: Dùng Schedule Groups để nhóm tasks có cùng cấu hình
Schedule::daily()
->onOneServer()
->timezone('America/New_York')
->group(function () {
Schedule::command('emails:send');
Schedule::command('emails:prune');
});
Lợi ích của Schedule Groups:
- Giảm lặp lại code: Không cần lặp lại
onOneServer(),timezone(),withoutOverlapping()cho từng task - Dễ maintain: Thay đổi cấu hình một lần áp dụng cho cả nhóm
- Tăng tính nhất quán: Đảm bảo tất cả tasks trong nhóm có cùng cấu hình
10. Timezone handling: Luôn nhất quán
Best practice: Cố định timezone theo business, không dùng server timezone. Nguyên tắc: Tất cả scheduled tasks phải dùng cùng một business timezone để đảm bảo tính nhất quán.
Ví dụ — Laravel 12 timezone:
Theo Laravel 12.x Scheduling Timezones, có 2 cách set timezone:
Cách 1: Set timezone trong config (khuyến nghị):
Khi tất cả tasks dùng cùng business timezone, thêm schedule_timezone vào config/app.php:
<?php
// config/app.php
return [
'timezone' => 'UTC', // Application timezone
'schedule_timezone' => 'Asia/Tokyo', // Business timezone cho scheduled tasks
];
Với cấu hình này, tất cả scheduled tasks sẽ tự động dùng timezone Asia/Tokyo trừ khi được ghi đè bởi method timezone() trong từng task cụ thể.
Cách 2: Set timezone cho từng task riêng:
Chỉ định timezone cho task cụ thể bằng method timezone():
<?php
// routes/console.php
use Illuminate\Support\Facades\Schedule;
// Set timezone cho task cụ thể (ghi đè config)
Schedule::command('report:generate')
->timezone('America/New_York')
->at('2:00');
Lưu ý quan trọng về DST (Daylight Saving Time):
Theo Laravel 12.x Scheduling Timezones, một số timezone sử dụng DST có thể ảnh hưởng đến thời gian thực thi. Khi DST thay đổi, task có thể chạy 2 lần hoặc không chạy. Nên tránh dùng timezone có DST khi có thể.
Nguyên tắc áp dụng:
- ✅ Nên: Set timezone một lần trong
config/app.phpvới keyschedule_timezonenếu tất cả tasks dùng cùng business timezone - ⚠️ Tránh: Set timezone cho từng task riêng lẻ → dễ quên, dễ sai, khó maintain
- ⚠️ Tránh: Dùng timezone có DST → có thể ảnh hưởng đến thời gian thực thi khi DST thay đổi
Kết luận: Framework cho quyết định kỹ thuật
Khi thêm một scheduled task mới, tôi tự hỏi 6 câu:
- Task này có side-effect quan trọng không? → Nếu có → Idempotent + audit batch
- Dữ liệu tăng thì task tăng theo tuyến nào? → Nếu O(N) theo bảng lớn → Phải có watermark/chunk/index
- Chạy trễ có làm sai cửa sổ dữ liệu không? → Nếu có → Cần
scheduledAt/batchAt - Có được phép chạy song song không? → Nếu không → Overlap guard + lock theo business key
- Nó thuộc priority nào? → Nếu không critical → Đừng để nó chạy chung queue với critical
- Fail thì ai biết, trong bao lâu? → Nếu câu trả lời mơ hồ → Bổ sung observability trước
Checklist áp dụng
- Scheduler chỉ dispatch queued jobs, không chạy logic nặng
- Tất cả job có side-effect đều idempotent
- Job dùng
batchTime/scheduledAtđể tính time window, không dùngnow() - Job dùng
chunkByIdhoặc cursor pagination cho data lớn - Job có stagger/rate-limit khi gọi external API
- Job log theo batch time để dễ đối soát
- Scheduler có helper methods theo domain, không phình to
schedule() - Timezone nhất quán: Business timezone, không dùng server timezone
- Queue được phân priority (critical/default/low)
- Có alert khi scheduler/job fail
Tài liệu tham khảo: Laravel 12.x Task Scheduling
45 comments
Thiss text iss priceless. Wheen can I finmd outt more?
Heree iss myy bllog pot porn2021.biz
Excelent bloog post. I definitely apprecciate this website.
Thanks!
Heree iis mmy website; xmxxtube.com – Pansy
–
References:
Lollybet Casino Erfahrungen cse.google.cz
References:
Lollybet App meine-schweiz.ru
I was very pleased to find this page. I wanted to
thank you for ones time for this fantastic read!! I definitely really liked every bit of it and I
have you book-marked to check out new information on your site.
I think this is among the most significant info for me.
And i’m glad reading your article. But should remark on some general things, The site style is perfect, the articles is really excellent : D.
Good job, cheers
Today, I went to the beachfront with my kids. I found a sea shell and gave it to my 4
year old daughter and said “You can hear the ocean if you put this to your ear.” She put the shell
to her ear and screamed. There was a hermit crab inside and it pinched
her ear. She never wants to go back! LoL I know this is entirely off topic but I had to tell someone!
If some one wishes to be updated with hottest technologies then he must be visit this web site and be up to date all the time.
Fantastic beat ! I would like to apprentice while you amend your site, how
can i subscribe for a weblog website? The account helped me a applicable
deal. I have been tiny bit familiar of this your broadcast provided vivid transparent
idea
This is my first time pay a visit at here and i am genuinely pleassant to read everthing at alone
place.
I like what you guys are up too. This type of
clever work and exposure! Keep up the wonderful works guys I’ve added you guys to our blogroll.
Terrific post but I was wanting to know if you could write a litte more on this topic?
I’d be very thankful if you could elaborate a little bit more.
Thanks!
Very good information. Lucky me I found your website by chance (stumbleupon).
I’ve saved it for later!
I’m impressed, I have to admit. Seldom do I encounter a blog that’s equally educative and engaging, and without a doubt, you have
hit the nail on the head. The problem is an issue that too few people are speaking intelligently about.
I’m very happy that I found this in my search for something concerning
this.
We stumbled over here coming from a different page and thought I should check
things out. I like what I see so now i am following you.
Look forward to looking into your web page yet again.
It’s very straightforward to find out any topic on web as compared to
books, as I found this paragraph at this website.
It’s not my first time to pay a quick visit this web page, i
am visiting this website dailly and take fastidious information from here
everyday.
I’m extremely impressed together with your writing skills
as smartly as with the structure for your weblog.
Is that this a paid subject matter or did you modify it your self?
Anyway stay up the nice high quality writing, it’s rare to look a nice blog like this one
nowadays..
Hi just wanted to give you a brief heads up and let you know a few
of the pictures aren’t loading correctly. I’m not sure why but I think its a linking
issue. I’ve tried it in two different internet browsers and both show
the same results.
Remarkable! Its actually awesome paragraph, I have got much clear
idea concerning from this article.
Keren sekali ulasannya! Indonesia memang memiliki destinasi wisata yang sangat
luar biasa. Saya sangat setuju bahwa Pesona Alam Indonesia adalah keindahan yang tak tergantikan, mulai dari
gunung hingga pantainya. Syukran sudah berbagi informasi
ini, sangat membantu saya merencanakan liburan berikutnya.
Jangan lupa kunjungi Wisata Alam Indonesia
yang lainnya juga! Wisata Alam Indonesia
Hello, i read your blog from time to time and i own a similar one and i was just wondering if you
get a lot of spam remarks? If so how do you prevent it, any plugin or anything you can advise?
I get so much lately it’s driving me crazy so any
support is very much appreciated.
This post is genuinely a fastidious one it assists new net users, who are wishing in favor of blogging.
Unquestionably consider that which you stated.
Your favorite reason appeared to be on the internet the simplest
thing to take note of. I say to you, I definitely get irked
while other folks think about concerns that
they just do not recognise about. You managed to hit the nail
upon the top as smartly as outlined out the whole thing without having side-effects , people can take
a signal. Will probably be back to get more. Thanks
Hmm it appears like your site ate my first comment (it was super long)
so I guess I’ll just sum it up what I wrote and say,
I’m thoroughly enjoying your blog. I too am
an aspiring blog writer but I’m still new to the whole thing.
Do you have any suggestions for newbie blog writers?
I’d certainly appreciate it.
As the admin of this website is working, no uncertainty very shortly it
will be famous, due to its quality contents.
Pretty section of content. I just stumbled upon your blog
and in accession capital to assert that I get actually enjoyed account
your blog posts. Anyway I’ll be subscribing to your feeds and even I achievement you access consistently
fast.
Reddyannaloginid.com: reddy anna login mobile registration https://Ekarange.com/reddy-anna-book-a-complete-overview-for-new-users/
Hey there, I think your website might be having browser compatibility
issues. When I look at your website in Chrome,
it looks fine but when opening in Internet Explorer, it has
some overlapping. I just wanted to give you a quick heads up!
Other then that, amazing blog!
WOW just what I was looking for. Came here by searching for raja89
Thanks for sharing such a nice thought, article is good, thats why i have read it
completely
It is the best time to make some plans for the future and
it is time to be happy. I’ve read this post and if I could I desire
to suggest you some interesting things or advice.
Perhaps you could write next articles referring to this article.
I wish to read more things about it!
Appreciate this post. Let me try it out.
This is very fascinating, You are a very professional blogger.
I’ve joined your rss feed and stay up for in quest of extra of your great post.
Also, I have shared your website in my social networks
I read this post completely concerning the resemblance of newest
and preceding technologies, it’s amazing article.
Thanks for sharing your thoughts about mcm168.
Regards
Thank you, I have recently been searching for information approximately this topic for a while
and yours is the greatest I have found out so
far. However, what in regards to the conclusion? Are you sure about the source?
Hello There. I found your blog using msn. This is an extremely well written article.
I’ll be sure to bookmark it and return to read more of your useful info.
Thanks for the post. I will definitely comeback.
I was able to find good info from your blog articles.
Do you have a spam problem on this site; I also am a blogger, and I was wondering your situation; many of us have created
some nice procedures and we are looking to swap techniques with
others, why not shoot me an email if interested.
Hi there, of course this piece of writing is really pleasant and I
have learned lot of things from it concerning blogging.
thanks.
bokep, bokep indo, porn, website penipu, bokep 3gp, sex, porno, xnxx, website scam,
scam, penipu
If you are going for best contents like I do, simply
visit this web page daily as it presents quality contents,
thanks
Hey there! I know this is kinda off topic but I was wondering which blog platform are you using
for this website? I’m getting sick and tired of WordPress because I’ve had issues with hackers and I’m looking
at alternatives for another platform. I would be
great if you could point me in the direction of a good platform.
I always used to read post in news papers but now as
I am a user of net therefore from now I am using net for
posts, thanks to web.
It’s hard to find knowledgeable people for this subject,
however, you sound like you know what you’re talking about!
Thanks