Skip to content

Commit

Permalink
Merge pull request #12 from achu-1612/ac/ref
Browse files Browse the repository at this point in the history
runner: ref handling restart of service
  • Loading branch information
achu-1612 authored Jan 10, 2025
2 parents efb8559 + 4a8dae9 commit 832990e
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 115 deletions.
48 changes: 28 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# glcm: Go Routine Lifecycle Management

```
___ ___ ___ ___
Expand All @@ -15,8 +16,6 @@
```



`glcm` is a Go package designed to manage the complete lifecycle of goroutines, providing a structured approach to starting, stopping, and monitoring services within your Go applications.

## Features
Expand All @@ -25,6 +24,7 @@
- **Lifecycle Management**: Control the startup and shutdown sequences of all registered services.
- **Service Control**: Individually start, stop, and restart services as needed.
- **Hooks Integration**: Define pre-run and post-run hooks for services to execute custom logic before starting or after stopping a service.
- **Auto-Restart with Backoff**: Automatically restart services with optional exponential backoff.

## Installation

Expand Down Expand Up @@ -107,27 +107,20 @@ if err != nil {
ctx := context.Background()

// BootUp boots up the runner. This will start all the registered services.
runner.BootUp(ctx)
```
### 6. Wait for the runner to stop
```go
// Wait waits for the runner to stop.
// Note: This is a blocking call. It is to be called after BootUp.
//Note: This is a blocking call. It is to be called after BootUp.
// Only a ShutDown() call will stop the runner.
// Even after all the registered services are stopped, runner would still be running.
runner.Wait()
// Even after all the registered services are stopped, runner would
runner.BootUp(ctx)
```
### 7. Shutdown the runner
### 6. Shutdown the runner
```go
// Shutdown shuts down the runner. This will stop all the registered services.
runner.Shutdown()
```
### 8. Stop service(s)
### 7. Stop service(s)
```go
// StopService stops the given list of services.
Expand All @@ -147,6 +140,23 @@ runner.RestartService("MyService1", "MyService2")
runner.RestartAllServices()
```
## Auto-Restart with Backoff
To enable auto-restart with backoff for a service, use the following options during service registration:
Note: The service will be restarted automatically only when `service.WithAutoRestart()` options is given while service registration and when the service exits automatically not by runner shutting it down.
```go
err := runner.RegisterService(
&MyService{},
service.WithAutoRestart(),
service.WithBackoff(),
service.WithMaxRetries(5), // Optional: Set maximum retries
service.WithBackoffExponent(2), // Optional: Set backoff exponent
)
if err != nil {
// Handle error
}
```
## Service Hooks
The `hook` package allows you to define hooks that execute before or after a service starts.
Expand Down Expand Up @@ -188,9 +198,7 @@ Contributions are welcome! Please submit issues and pull requests for any improv
This project is licensed under the MIT License.
## TODO
- Support for timeout for go-routine shutdowns (if possible)
- Better error handling for the pre and post hooks for service
- Service dependency
- Auto restart config for services
- Exponential back-off restart for restart of service
- Support for Job with scheduling.
- Support for timeout for go-routine shutdowns (if possible).
- Better error handling for the pre and post hooks for service.
- Service dependency.
9 changes: 5 additions & 4 deletions example/advanced/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"fmt"
"log"
"os"
"syscall"
Expand Down Expand Up @@ -76,15 +75,17 @@ func main() {

process, err := os.FindProcess(os.Getpid())
if err != nil {
fmt.Printf("Error finding process: %s\n", err)
log.Printf("Error finding process: %s\n", err)
return
}

if err := process.Signal(syscall.SIGTERM); err != nil {
fmt.Printf("Error sending termination signal: %s\n", err)
log.Printf("Error sending termination signal: %s\n", err)
}

}()

base.BootUp(context.TODO())
if err := base.BootUp(context.TODO()); err != nil {
log.Fatalf("Error while booting up the runner: %v", err)
}
}
10 changes: 5 additions & 5 deletions example/auto-restart/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"fmt"
"log"
"os"
"syscall"
Expand Down Expand Up @@ -51,16 +50,17 @@ func main() {

process, err := os.FindProcess(os.Getpid())
if err != nil {
fmt.Printf("Error finding process: %s\n", err)
log.Printf("Error finding process: %s\n", err)
return
}

if err := process.Signal(syscall.SIGTERM); err != nil {
fmt.Printf("Error sending termination signal: %s\n", err)
log.Printf("Error sending termination signal: %s\n", err)
}

}()

base.BootUp(context.TODO())
// base.Wait()
if err := base.BootUp(context.TODO()); err != nil {
log.Fatalf("Error while booting up the runner: %v", err)
}
}
10 changes: 5 additions & 5 deletions example/backoff/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"fmt"
"log"
"os"
"syscall"
Expand Down Expand Up @@ -30,16 +29,17 @@ func main() {

process, err := os.FindProcess(os.Getpid())
if err != nil {
fmt.Printf("Error finding process: %s\n", err)
log.Printf("Error finding process: %s\n", err)
return
}

if err := process.Signal(syscall.SIGTERM); err != nil {
fmt.Printf("Error sending termination signal: %s\n", err)
log.Printf("Error sending termination signal: %s\n", err)
}

}()

base.BootUp(context.TODO())
// base.Wait()
if err := base.BootUp(context.TODO()); err != nil {
log.Fatalf("Error while booting up the runner: %v", err)
}
}
9 changes: 5 additions & 4 deletions example/bootup/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"fmt"
"log"
"os"
"syscall"
Expand Down Expand Up @@ -50,15 +49,17 @@ func main() {

process, err := os.FindProcess(os.Getpid())
if err != nil {
fmt.Printf("Error finding process: %s\n", err)
log.Printf("Error finding process: %s\n", err)
return
}

if err := process.Signal(syscall.SIGTERM); err != nil {
fmt.Printf("Error sending termination signal: %s\n", err)
log.Printf("Error sending termination signal: %s\n", err)
}

}()

base.BootUp(context.TODO())
if err := base.BootUp(context.TODO()); err != nil {
log.Fatalf("Error while booting up the runner: %v", err)
}
}
9 changes: 5 additions & 4 deletions example/restart/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"fmt"
"log"
"os"
"syscall"
Expand Down Expand Up @@ -66,15 +65,17 @@ func main() {

process, err := os.FindProcess(os.Getpid())
if err != nil {
fmt.Printf("Error finding process: %s\n", err)
log.Printf("Error finding process: %s\n", err)
return
}

if err := process.Signal(syscall.SIGTERM); err != nil {
fmt.Printf("Error sending termination signal: %s\n", err)
log.Printf("Error sending termination signal: %s\n", err)
}

}()

base.BootUp(context.TODO())
if err := base.BootUp(context.TODO()); err != nil {
log.Fatalf("Error while booting up the runner: %v", err)
}
}
9 changes: 5 additions & 4 deletions example/stop/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"fmt"
"log"
"os"
"syscall"
Expand Down Expand Up @@ -66,15 +65,17 @@ func main() {

process, err := os.FindProcess(os.Getpid())
if err != nil {
fmt.Printf("Error finding process: %s\n", err)
log.Printf("Error finding process: %s\n", err)
return
}

if err := process.Signal(syscall.SIGTERM); err != nil {
fmt.Printf("Error sending termination signal: %s\n", err)
log.Printf("Error sending termination signal: %s\n", err)
}

}()

base.BootUp(context.TODO())
if err := base.BootUp(context.TODO()); err != nil {
log.Fatalf("Error while booting up the runner: %v", err)
}
}
5 changes: 2 additions & 3 deletions runner/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import (
// Base is the blueprint for the runner.
type Base interface {
// BootUp boots up the runner. This will start all the registered services.
// Note: This is a blocking call. It is to be called after BootUp.
// Only a ShutDown() call will stop the runner.
// Note: This is a blocking call. Only a ShutDown() or Term signal to process will stop the runner.
// Even after all the registered services are stopped, runner would still be running.
BootUp(context.Context)
BootUp(context.Context) error

// Shutdown shuts down the runner. This will stop all the registered services.
Shutdown()
Expand Down
12 changes: 0 additions & 12 deletions runner/base.mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions runner/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package runner
import "errors"

var (
ErrServiceAlreadyExists = errors.New("service already exists")
ErrRunnerAlreadyRunning = errors.New("runner already running")
ErrRegisterServiceAlreadyExists = errors.New("service already exists")
ErrRunnerAlreadyRunning = errors.New("runner already running")
ErrRegisterNilService = errors.New("can not register nil service")
)
Loading

0 comments on commit 832990e

Please sign in to comment.