DEV Community

Just a Side Project
Just a Side Project

Posted on Originally published at justasideproject.blogspot.com

The Silent Scheduled-Task Failure Nobody Warns You About (And How I Caught It)

Last week, a blog post I had scheduled to auto-publish at 9pm simply didn't. No error in my inbox, no crash log, nothing. Windows Task Scheduler's own history said the task had run and succeeded. It hadn't. Here's what was actually going on, because the failure mode is a lot more common than the one blog post I eventually found on it suggested.

The setup

My publishing pipeline is a Python script (publish.py) wrapped in a small PowerShell script, registered as a Windows Task Scheduler job set to fire at a specific time even if the machine is asleep (WakeToRun). The work PC sleeps overnight, wakes itself for the scheduled task, runs the script, goes back to sleep. That part works reliably.

Why Task Scheduler said "success" when it wasn't

The Python script failed with a DNS resolution error trying to reach oauth2.googleapis.com -- the machine had woken up, but the network adapter hadn't finished reconnecting yet. That part is almost expected; waking from sleep isn't instant. The part that actually cost me a missed post is this:

PowerShell does not automatically propagate a wrapped native command's exit code as its own. When my .ps1 script called python publish.py ... and Python exited with a non-zero code, the PowerShell script itself still exited 0 unless I explicitly checked and re-threw that code. Task Scheduler only sees the PowerShell wrapper's exit code -- so from its point of view, the task ran cleanly. "Last Run Result: 0x0" doesn't mean the thing inside your script worked. It means your wrapper didn't crash.

Task Scheduler's report What actually happened
Before the fix "Last Run Result: 0x0" (success) Post never went live -- DNS lookup for oauth2.googleapis.com failed
After the fix "Last Run Result: 0x0" (success) Script waits for a real connection first, then publishes correctly

The fix

Two changes closed the gap. First, don't let the script even attempt the API call until the network is actually back:

# Wait for a real network connection before doing anything else (up to 5 min)
$connected = $false
for ($i = 0; $i -lt 30; $i++) {
    if (Test-Connection -ComputerName "8.8.8.8" -Count 1 -Quiet -ErrorAction SilentlyContinue) {
        $connected = $true
        break
    }
    Start-Sleep -Seconds 10
}
if (-not $connected) {
    Add-Content -Path "$PSScriptRoot\publish_log.txt" -Value "$(Get-Date): network unavailable, publish cancelled"
    exit 1
}

python publish.py "post.html" --title "..." --publish-live *>> publish_log.txt

Second -- and this is the one I'd skip if I were being lazy -- I now treat "Last Run Result: 0x0" as necessary but not sufficient. The wrapper script logs its own timestamped success/failure line to a text file, and that log, not the Task Scheduler history, is what I actually check.

If you're scheduling anything that wakes a sleeping machine

The general shape of this bug isn't specific to Blogger, Python, or even PowerShell -- it's "the task fired before its dependency was ready, and the wrapper swallowed the failure." Anywhere you see WakeToRun or an equivalent, ask two questions: does the very first thing the script does depend on network/disk/another service being ready, and does a failure inside the wrapped process actually surface as a failure to whatever is monitoring the job? If the answer to either is "not sure," it's worth testing deliberately -- unplug the network, run the task, and see what the scheduler reports.

Top comments (0)