@@ -1620,7 +1620,11 @@ DispatchResult Service::InvokeCmd(const CommandId* cid, CmdArgList tail_args,
16201620 // We are not sending any admin command in the monitor, and we do not want to
16211621 // do any processing if we don't have any waiting connections with monitor
16221622 // enabled on them - see https://redis.io/commands/monitor/
1623- if (!ServerState::tlocal ()->Monitors ().Empty () && (cid->opt_mask () & CO::ADMIN) == 0 ) {
1623+ // For EXEC command specifically, we dispatch monitor after executing all queued commands
1624+ // to preserve correct ordering (MULTI, commands, EXEC) instead of (MULTI, EXEC, commands)
1625+ bool should_dispatch_monitor = !ServerState::tlocal ()->Monitors ().Empty () &&
1626+ (cid->opt_mask () & CO::ADMIN) == 0 && cid != exec_cid_;
1627+ if (should_dispatch_monitor) {
16241628 DispatchMonitor (cntx, cid, tail_args);
16251629 }
16261630
@@ -2585,6 +2589,13 @@ void Service::Exec(CmdArgList args, const CommandContext& cmd_cntx) {
25852589 }
25862590
25872591 cntx->cid = exec_cid_;
2592+
2593+ // Dispatch EXEC to monitor after all queued commands have been executed
2594+ // to preserve correct ordering (MULTI, commands, EXEC)
2595+ if (!ServerState::tlocal ()->Monitors ().Empty () && (exec_cid_->opt_mask () & CO::ADMIN) == 0 ) {
2596+ DispatchMonitor (cntx, exec_cid_, args);
2597+ }
2598+
25882599 VLOG (2 ) << " Exec completed" ;
25892600}
25902601
0 commit comments