package herojobs import ( "context" "fmt" "time" "github.com/go-redis/redis/v8" ) const ( defaultRedisURL = "redis://localhost:6379/0" ) // Factory manages job-related operations, including Redis connectivity and watchdog. type Factory struct { redisClient *redis.Client // Add other fields as needed, e.g., for watchdog } // NewFactory creates a new Factory instance. // It takes a redisURL string; if empty, it defaults to defaultRedisURL. func NewFactory(redisURL string) (*Factory, error) { if redisURL == "" { redisURL = defaultRedisURL } opt, err := redis.ParseURL(redisURL) if err != nil { return nil, fmt.Errorf("invalid redis URL: %w", err) } client := redis.NewClient(opt) // Check connection to Redis ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _, err = client.Ping(ctx).Result() if err != nil { return nil, fmt.Errorf("failed to connect to redis at %s: %w", redisURL, err) } fmt.Printf("Successfully connected to Redis at %s\n", redisURL) factory := &Factory{ redisClient: client, } // TODO: Properly start the watchdog here fmt.Println("Watchdog placeholder: Watchdog would be started here.") return factory, nil } // Close closes the Redis client connection. func (f *Factory) Close() error { if f.redisClient != nil { return f.redisClient.Close() } return nil } // GetJob retrieves a job by its ID from Redis. func (f *Factory) GetJob(ctx context.Context, jobID string) (string, error) { // Example: Assuming jobs are stored as string values val, err := f.redisClient.Get(ctx, jobID).Result() if err == redis.Nil { return "", fmt.Errorf("job with ID %s not found", jobID) } else if err != nil { return "", fmt.Errorf("failed to get job %s from redis: %w", jobID, err) } return val, nil } // ListJobs lists all job IDs (or a subset) from Redis. // This is a simplified example; real-world job listing might involve more complex data structures. func (f *Factory) ListJobs(ctx context.Context) ([]string, error) { // Example: List all keys that might represent jobs. // In a real application, you'd likely use specific Redis data structures (e.g., sorted sets, hashes) // to manage jobs more efficiently and avoid scanning all keys. keys, err := f.redisClient.Keys(ctx, "job:*").Result() // Assuming job keys are prefixed with "job:" if err != nil { return nil, fmt.Errorf("failed to list jobs from redis: %w", err) } return keys, nil } // AddJob adds a new job to Redis. func (f *Factory) AddJob(ctx context.Context, jobID string, jobData string) error { // Example: Store job data as a string err := f.redisClient.Set(ctx, jobID, jobData, 0).Err() // 0 for no expiration if err != nil { return fmt.Errorf("failed to add job %s to redis: %w", jobID, err) } return nil } // DeleteJob deletes a job from Redis. func (f *Factory) DeleteJob(ctx context.Context, jobID string) error { _, err := f.redisClient.Del(ctx, jobID).Result() if err != nil { return fmt.Errorf("failed to delete job %s from redis: %w", jobID, err) } return nil }