[{"data":1,"prerenderedAt":488},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fheartbeats":3},{"id":4,"title":5,"body":6,"description":480,"extension":481,"meta":482,"navigation":483,"path":484,"seo":485,"stem":486,"__hash__":487},"docs\u002Fdocs\u002F11.heartbeats.md","Heartbeats",{"type":7,"value":8,"toc":465},"minimark",[9,13,17,20,23,28,53,57,110,114,151,155,160,163,167,174,184,187,249,253,256,259,263,266,272,287,291,297,340,347,352,399,404,421,425,428,449,453,461],[10,11,5],"h1",{"id":12},"heartbeats",[14,15,16],"p",{},"A heartbeat is an inverted monitor: instead of Vantaj reaching out to check something, your job reaches in to say \"I ran successfully.\" If the ping stops arriving, Vantaj alerts you.",[14,18,19],{},"This makes heartbeats the right tool for things that can fail silently - a cron job that crashes before completing, a backup script that never starts because the server rebooted, a worker process that stopped without raising an error.",[21,22],"heartbeats-demo",{},[24,25,27],"h2",{"id":26},"how-it-works","How it works",[29,30,31,35,38,41],"ol",{},[32,33,34],"li",{},"You create a heartbeat and set how often your job is expected to run",[32,36,37],{},"Vantaj gives you a unique ping URL",[32,39,40],{},"Your job calls that URL at the end of each successful run",[32,42,43,44,48,49],{},"Vantaj checks every minute: if no ping has arrived within ",[45,46,47],"code",{},"interval + grace",", the heartbeat is marked ",[50,51,52],"strong",{},"missed",[24,54,56],{"id":55},"status-values","Status values",[58,59,60,73],"table",{},[61,62,63],"thead",{},[64,65,66,70],"tr",{},[67,68,69],"th",{},"Status",[67,71,72],{},"Meaning",[74,75,76,87,100],"tbody",{},[64,77,78,84],{},[79,80,81],"td",{},[45,82,83],{},"Healthy",[79,85,86],{},"A ping arrived within the expected window",[64,88,89,94],{},[79,90,91],{},[45,92,93],{},"Missed",[79,95,96,97],{},"No ping arrived within ",[45,98,99],{},"interval + grace period",[64,101,102,107],{},[79,103,104],{},[45,105,106],{},"Waiting",[79,108,109],{},"Heartbeat was just created and no ping has been received yet",[24,111,113],{"id":112},"creating-a-heartbeat","Creating a heartbeat",[29,115,116,122,128,139,142,145],{},[32,117,118,119,121],{},"Go to ",[50,120,5],{}," in the left navigation",[32,123,124,125],{},"Click ",[50,126,127],{},"New heartbeat",[32,129,130,131,134,135,138],{},"Give it a name (e.g. ",[45,132,133],{},"Nightly backup",", ",[45,136,137],{},"Invoice sync",")",[32,140,141],{},"Set the schedule type and expected interval",[32,143,144],{},"Set a grace period",[32,146,124,147,150],{},[50,148,149],{},"Create heartbeat"," - you'll see the ping URL immediately",[24,152,154],{"id":153},"schedule-types","Schedule types",[156,157,159],"h3",{"id":158},"interval","Interval",[14,161,162],{},"Choose a preset interval - every 5 minutes, every hour, every day, and so on. Vantaj expects a ping every N minutes, plus the grace period.",[156,164,166],{"id":165},"cron","Cron",[14,168,169,170,173],{},"Enter a cron expression (e.g. ",[45,171,172],{},"0 3 * * *"," for 3 AM daily) and select a timezone. Use this when your job runs at a specific time of day rather than on a rolling interval.",[175,176,181],"pre",{"className":177,"code":179,"language":180},[178],"language-text","minute · hour · day-of-month · month · day-of-week\n","text",[45,182,179],{"__ignoreMap":183},"",[14,185,186],{},"Common examples:",[58,188,189,198],{},[61,190,191],{},[64,192,193,196],{},[67,194,195],{},"Expression",[67,197,72],{},[74,199,200,210,220,229,239],{},[64,201,202,207],{},[79,203,204],{},[45,205,206],{},"* * * * *",[79,208,209],{},"Every minute",[64,211,212,217],{},[79,213,214],{},[45,215,216],{},"0 * * * *",[79,218,219],{},"Every hour",[64,221,222,226],{},[79,223,224],{},[45,225,172],{},[79,227,228],{},"Every day at 3 AM",[64,230,231,236],{},[79,232,233],{},[45,234,235],{},"0 9 * * 1",[79,237,238],{},"Every Monday at 9 AM",[64,240,241,246],{},[79,242,243],{},[45,244,245],{},"0 0 1 * *",[79,247,248],{},"First day of every month",[24,250,252],{"id":251},"grace-period","Grace period",[14,254,255],{},"The grace period is extra time Vantaj waits after the expected interval before marking a heartbeat as missed. Use it to absorb legitimate delays - a job that usually runs in 30 seconds but occasionally takes 2 minutes under load.",[14,257,258],{},"For example, with a 1-hour interval and 5-minute grace, a heartbeat is marked missed only if no ping arrives within 1 hour and 5 minutes of the previous ping.",[24,260,262],{"id":261},"the-ping-url","The ping URL",[14,264,265],{},"Each heartbeat has a unique URL like:",[175,267,270],{"className":268,"code":269,"language":180},[178],"https:\u002F\u002Fapp.vantaj.co\u002Fapi\u002Fhb\u002F\u003Ctoken>\n",[45,271,269],{"__ignoreMap":183},[14,273,274,275,278,279,282,283,286],{},"Call it with ",[45,276,277],{},"GET"," or ",[45,280,281],{},"POST"," - both work. Call it ",[50,284,285],{},"after"," your job completes successfully, not before. If your job fails partway through, don't call it - the missed ping is the signal.",[24,288,290],{"id":289},"integration-examples","Integration examples",[14,292,293,296],{},[50,294,295],{},"Shell \u002F cron"," - append to your cron command:",[175,298,302],{"className":299,"code":300,"language":301,"meta":183,"style":183},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","your-job && curl -fsS -m 10 --retry 3 https:\u002F\u002Fapp.vantaj.co\u002Fapi\u002Fhb\u002FYOUR_TOKEN\n","bash",[45,303,304],{"__ignoreMap":183},[305,306,309,313,317,320,324,327,331,334,337],"span",{"class":307,"line":308},"line",1,[305,310,312],{"class":311},"sBMFI","your-job",[305,314,316],{"class":315},"sMK4o"," &&",[305,318,319],{"class":311}," curl",[305,321,323],{"class":322},"sfazB"," -fsS",[305,325,326],{"class":322}," -m",[305,328,330],{"class":329},"sbssI"," 10",[305,332,333],{"class":322}," --retry",[305,335,336],{"class":329}," 3",[305,338,339],{"class":322}," https:\u002F\u002Fapp.vantaj.co\u002Fapi\u002Fhb\u002FYOUR_TOKEN\n",[14,341,342,343,346],{},"The ",[45,344,345],{},"&&"," ensures the ping only fires if the job exits with code 0.",[14,348,349],{},[50,350,351],{},"Node.js:",[175,353,357],{"className":354,"code":355,"language":356,"meta":183,"style":183},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","await runYourJob();\nawait fetch('https:\u002F\u002Fapp.vantaj.co\u002Fapi\u002Fhb\u002FYOUR_TOKEN');\n","js",[45,358,359,376],{"__ignoreMap":183},[305,360,361,365,369,373],{"class":307,"line":308},[305,362,364],{"class":363},"s7zQu","await",[305,366,368],{"class":367},"s2Zo4"," runYourJob",[305,370,372],{"class":371},"sTEyZ","()",[305,374,375],{"class":315},";\n",[305,377,379,381,384,387,390,393,395,397],{"class":307,"line":378},2,[305,380,364],{"class":363},[305,382,383],{"class":367}," fetch",[305,385,386],{"class":371},"(",[305,388,389],{"class":315},"'",[305,391,392],{"class":322},"https:\u002F\u002Fapp.vantaj.co\u002Fapi\u002Fhb\u002FYOUR_TOKEN",[305,394,389],{"class":315},[305,396,138],{"class":371},[305,398,375],{"class":315},[14,400,401],{},[50,402,403],{},"Python:",[175,405,409],{"className":406,"code":407,"language":408,"meta":183,"style":183},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","run_your_job()\nrequests.get('https:\u002F\u002Fapp.vantaj.co\u002Fapi\u002Fhb\u002FYOUR_TOKEN', timeout=10)\n","python",[45,410,411,416],{"__ignoreMap":183},[305,412,413],{"class":307,"line":308},[305,414,415],{},"run_your_job()\n",[305,417,418],{"class":307,"line":378},[305,419,420],{},"requests.get('https:\u002F\u002Fapp.vantaj.co\u002Fapi\u002Fhb\u002FYOUR_TOKEN', timeout=10)\n",[24,422,424],{"id":423},"ping-history","Ping history",[14,426,427],{},"The heartbeat detail page shows:",[429,430,431,437,443],"ul",{},[32,432,433,436],{},[50,434,435],{},"Last ping"," - how long ago the most recent ping arrived, updating live",[32,438,439,442],{},[50,440,441],{},"Last 24 hours"," - hourly bar chart of ping activity",[32,444,445,448],{},[50,446,447],{},"Recent pings"," - a log of the last 20 pings with timestamp, method, user-agent, and IP",[24,450,452],{"id":451},"what-heartbeats-dont-replace","What heartbeats don't replace",[14,454,455,456,460],{},"Heartbeats monitor ",[457,458,459],"em",{},"whether"," a job ran - not whether it ran correctly. If your backup script runs but backs up 0 bytes, it will still ping successfully. Combine heartbeats with application-level checks (e.g. verify the backup file exists and has a non-zero size before calling the ping URL) for deeper coverage.",[462,463,464],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":183,"searchDepth":378,"depth":378,"links":466},[467,468,469,470,475,476,477,478,479],{"id":26,"depth":378,"text":27},{"id":55,"depth":378,"text":56},{"id":112,"depth":378,"text":113},{"id":153,"depth":378,"text":154,"children":471},[472,474],{"id":158,"depth":473,"text":159},3,{"id":165,"depth":473,"text":166},{"id":251,"depth":378,"text":252},{"id":261,"depth":378,"text":262},{"id":289,"depth":378,"text":290},{"id":423,"depth":378,"text":424},{"id":451,"depth":378,"text":452},"Monitor scheduled jobs and background workers by expecting regular pings","md",{},true,"\u002Fdocs\u002Fheartbeats",{"title":5,"description":480},"docs\u002F11.heartbeats","02AR9R1MjqQniqhUhjUcTPH9zv6ZVsizMBgUMdsTUgQ",1783289834316]