🐹

Go SDK

v0.1.2

Official Go SDK for CronBeats ping telemetry. Lightweight package with explicit error handling and zero external dependencies.

Installation

Install via go get:

go get github.com/cronbeats/cronbeats-go

Requirements: Go 1.19 or higher

Quick Start

Send a simple ping to mark your cron job as successful:

package main

import (
	"log"
	cronbeatsgo "github.com/cronbeats/cronbeats-go"
)

func main() {
	client, err := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
	if err != nil {
		log.Fatal(err)
	}
	
	_, err = client.Ping()
	if err != nil {
		log.Fatal(err)
	}
	
	// Done! CronBeats knows your job ran successfully.
}

Sending Pings

Simple Ping

Send a single heartbeat when your job completes:

client, _ := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
_, err := client.Ping()
// Handle err

Start & End Signals

Track execution time by signaling when your job starts and ends:

client, _ := cronbeatsgo.NewPingClient("YCrXzYbV", nil)

client.Start()
// ... do your work ...
client.Success()  // or client.Fail() on error

Real-World Cron Job Example

Complete example with error handling:

package main

import (
	"log"
	cronbeatsgo "github.com/cronbeats/cronbeats-go"
)

func runCronTask() error {
	// Your actual work here
	return processEmails()
}

func main() {
	client, err := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
	if err != nil {
		log.Fatal(err)
	}
	
	client.Start()
	
	if err := runCronTask(); err != nil {
		client.Fail()
		log.Fatal(err)
	}
	
	client.Success()
}

Progress Tracking

Send real-time progress updates from long-running jobs. CronBeats displays a live progress bar and status message on your dashboard.

📊 Two Progress Modes

Mode 1: With Percentageclient.Progress(50, "message")

Dashboard shows progress bar (0-100%) + your message. Use when you can calculate meaningful progress.

Mode 2: Message Onlyclient.Progress(nil, "message")

Dashboard shows only your status message (no percentage bar). Use for status updates without measurable progress.

Basic Progress Update

// Send progress percentage (0-100) with status message
seq := 50
client.Progress(cronbeatsgo.ProgressOptions{
	Seq:     &seq,
	Message: "Processing batch 50/100",
})

Processing Records Example

package main

import (
	"fmt"
	cronbeatsgo "github.com/cronbeats/cronbeats-go"
)

func main() {
	client, _ := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
	client.Start()
	
	total := 10000
	for i := 1; i <= total; i++ {
		processRecord(i)
		
		// Update progress every 500 records
		if i%500 == 0 {
			seq := i * 100 / total
			client.Progress(cronbeatsgo.ProgressOptions{
				Seq:     &seq,
				Message: fmt.Sprintf("Processed %d / %d records", i, total),
			})
		}
	}
	
	seq := 100
	client.Progress(cronbeatsgo.ProgressOptions{
		Seq:     &seq,
		Message: "All records processed",
	})
	client.Success()
}

Database Backup with defer

package main

import (
	"log"
	"os/exec"
	cronbeatsgo "github.com/cronbeats/cronbeats-go"
)

func main() {
	client, _ := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
	client.Start()
	
	// Ensure we report failure if panic or early return
	success := false
	defer func() {
		if !success {
			client.Fail()
		}
	}()
	
	seq := 10
	client.Progress(cronbeatsgo.ProgressOptions{Seq: &seq, Message: "Starting backup..."})
	
	// Dump database
	if err := exec.Command("pg_dump", "mydb").Run(); err != nil {
		log.Fatal(err)
	}
	seq = 50
	client.Progress(cronbeatsgo.ProgressOptions{Seq: &seq, Message: "Database dumped"})
	
	// Compress
	if err := exec.Command("gzip", "backup.sql").Run(); err != nil {
		log.Fatal(err)
	}
	seq = 100
	client.Progress(cronbeatsgo.ProgressOptions{Seq: &seq, Message: "Backup complete"})
	
	client.Success()
	success = true
}

Error Handling

The SDK returns errors for validation and API issues. Always check the error return value:

package main

import (
	"errors"
	"log"
	cronbeatsgo "github.com/cronbeats/cronbeats-go"
)

func main() {
	client, err := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
	if err != nil {
		// Validation error: invalid job key format
		log.Fatalf("Client creation failed: %v", err)
	}
	
	_, err = client.Ping()
	if err != nil {
		// API/network error
		// SDK already retried if appropriate
		log.Printf("Ping failed: %v", err)
		// Continue execution - don't block cron job
	}
}

API Reference

Method Description
Ping() (PingResponse, error) Send a simple heartbeat ping
Start() (PingResponse, error) Signal job start and begin execution timer
End(status) (PingResponse, error) Signal job end with status ("success" or "fail")
Success() (PingResponse, error) Alias for End("success")
Fail() (PingResponse, error) Alias for End("fail")
Progress(opts) (PingResponse, error) Send progress update with ProgressOptions{Seq, Message}

For complete API documentation, see the pkg.go.dev reference.

Configuration Options

Customize the client behavior:

baseURL := "https://cronbeats.io"
timeoutMs := 5000
maxRetries := 2

client, err := cronbeatsgo.NewPingClient("YCrXzYbV", &cronbeatsgo.PingClientOptions{
	BaseURL:    &baseURL,
	TimeoutMs:  &timeoutMs,
	MaxRetries: &maxRetries,
})

Note: The default 5-second timeout ensures the SDK never blocks your cron job if CronBeats is unreachable. Adjust only if you need longer waits.

Complete Examples

Background Job with Context

package main

import (
	"context"
	"fmt"
	"time"
	cronbeatsgo "github.com/cronbeats/cronbeats-go"
)

func processData(ctx context.Context, client *cronbeatsgo.PingClient) error {
	client.Start()
	defer func() {
		// Ensure we report failure if panic
		if r := recover(); r != nil {
			client.Fail()
			panic(r)
		}
	}()
	
	steps := []struct {
		pct int
		msg string
		fn  func() error
	}{
		{10, "Step 1: Extract", extractData},
		{40, "Step 2: Transform", transformData},
		{70, "Step 3: Load", loadData},
		{90, "Step 4: Validate", validateData},
	}
	
	for _, step := range steps {
		select {
		case <-ctx.Done():
			client.Fail()
			return ctx.Err()
		default:
			client.Progress(cronbeatsgo.ProgressOptions{
				Seq:     &step.pct,
				Message: step.msg,
			})
			if err := step.fn(); err != nil {
				client.Fail()
				return err
			}
		}
	}
	
	seq := 100
	client.Progress(cronbeatsgo.ProgressOptions{Seq: &seq, Message: "Complete"})
	client.Success()
	return nil
}

func main() {
	client, _ := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
	
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
	defer cancel()
	
	if err := processData(ctx, client); err != nil {
		fmt.Printf("Job failed: %v\n", err)
	}
}

Concurrent Workers

package main

import (
	"sync"
	"sync/atomic"
	cronbeatsgo "github.com/cronbeats/cronbeats-go"
)

func main() {
	client, _ := cronbeatsgo.NewPingClient("YCrXzYbV", nil)
	client.Start()
	
	total := 10000
	var processed atomic.Int32
	var wg sync.WaitGroup
	
	// Process in batches with 10 workers
	batchSize := 100
	for i := 0; i < total; i += batchSize {
		wg.Add(1)
		go func(start int) {
			defer wg.Done()
			for j := start; j < start+batchSize && j < total; j++ {
				processRecord(j)
				count := processed.Add(1)
				
				// Report progress periodically
				if count%500 == 0 {
					seq := int(count * 100 / int32(total))
					client.Progress(cronbeatsgo.ProgressOptions{
						Seq:     &seq,
						Message: "Processing records...",
					})
				}
			}
		}(i)
	}
	
	wg.Wait()
	seq := 100
	client.Progress(cronbeatsgo.ProgressOptions{Seq: &seq, Message: "Complete"})
	client.Success()
}

Ready to Get Started?

Install the SDK and start monitoring your Go cron jobs in minutes