fix: remove nextRun recalculation from getAgents() that blocked cron
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 42s

The getAgents() function was recalculating nextRun to future dates when
it found past values. This prevented the cron scheduler from ever
finding due agents (nextRun <= now was always false since getAgents
had already pushed it to the future).

Also fix toast polling: use null sentinel for agents without initial
actions so first execution is still detected. Limit cron to 3 agents
per cycle and add logging.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 13:00:55 +02:00
parent 1b4c6123c2
commit f0999263a0
3 changed files with 14 additions and 30 deletions

View File

@@ -91,16 +91,15 @@ export function AgentsPageClient({
}, [])
// Track latest action per agent to detect new executions
const prevActionsRef = useRef<Record<string, string>>({})
// null = agent tracked with no initial actions, undefined = not tracked yet
const prevActionsRef = useRef<Record<string, string | null>>({})
// Poll every 30s to detect agent executions and show toast notifications
useEffect(() => {
// Initialize tracking from initial data
// Initialize tracking from initial data — use null for agents without actions
// so we can still detect their FIRST execution
for (const agent of initialAgents) {
const lastAction = agent.actions[0]
if (lastAction) {
prevActionsRef.current[agent.id] = lastAction.id
}
prevActionsRef.current[agent.id] = agent.actions[0]?.id ?? null
}
const interval = setInterval(async () => {
@@ -112,8 +111,11 @@ export function AgentsPageClient({
if (!lastAction) continue
const prevId = prevActionsRef.current[agent.id]
if (prevId && prevId !== lastAction.id) {
// New action detected
// undefined = agent not in initial list (created by someone else, skip)
if (prevId === undefined) continue
if (prevId !== lastAction.id) {
// New execution detected (first action ever, or new run)
if (lastAction.status === 'success') {
toast.success(t('agents.toasts.autoRunSuccess', { name: agent.name }))
} else if (lastAction.status === 'failure') {

View File

@@ -206,26 +206,6 @@ export async function getAgents() {
orderBy: { createdAt: 'desc' }
})
// Fix stale nextRun: recalculate if in the past for scheduled agents
const now = new Date()
for (const agent of agents) {
if (agent.frequency !== 'manual' && agent.nextRun && new Date(agent.nextRun) < now) {
const nextRun = calculateNextRun({
frequency: agent.frequency,
scheduledTime: agent.scheduledTime,
scheduledDay: agent.scheduledDay,
timezone: agent.timezone,
})
if (nextRun) {
await prisma.agent.update({
where: { id: agent.id },
data: { nextRun },
})
agent.nextRun = nextRun
}
}
}
return agents
} catch (error) {
console.error('Error fetching agents:', error)

View File

@@ -46,10 +46,12 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ success: true, executed: 0 })
}
console.log(`[CronAgents] Found ${dueAgents.length} due agent(s)`)
const results: { id: string; success: boolean; error?: string }[] = []
// Execute agents sequentially to avoid overwhelming the AI provider
for (const agent of dueAgents) {
// Execute agents sequentially (max 3 per cycle) to avoid overwhelming the AI provider
for (const agent of dueAgents.slice(0, 3)) {
try {
const { executeAgent } = await import('@/lib/ai/services/agent-executor.service')
const result = await executeAgent(agent.id, agent.userId)