Golet can manage many services with goroutine from one golang program. It's like a supervisor.
It supports go version 1.7 or higher. Golet is based on the idea of Proclet.
Proclet is a great module in Perl.
package main
import (
"context"
"fmt"
"net/http"
"strings"
"syscall"
"time"
"github.com/Code-Hex/golet"
)
func main() {
p := golet.New(context.Background())
p.EnableColor()
// Execution interval
p.SetInterval(time.Second * 1)
p.Env(map[string]string{
"NAME": "codehex",
"VALUE": "121",
})
p.Add(
golet.Service{
Exec: "plackup --port $PORT",
Tag: "plack",
},
golet.Service{
Exec: "echo 'This is cron!!'",
Every: "30 * * * * *",
Worker: 2,
Tag: "cron",
},
)
p.Add(golet.Service{
Code: func(ctx context.Context) error {
c := ctx.(*golet.Context)
c.Println("Hello golet!! Port:", c.Port())
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World")
buf := strings.NewReader("This is log string\nNew line1\nNew line2\nNew line3\n")
c.Copy(buf)
})
go http.ListenAndServe(c.ServePort(), mux)
for {
select {
// You can notify signal received.
case <-c.Recv():
signal, err := c.Signal()
if err != nil {
c.Println(err.Error())
return err
}
switch signal {
case syscall.SIGTERM, syscall.SIGHUP, syscall.SIGINT:
c.Println(signal.String())
return nil
}
case <-ctx.Done():
return nil
}
}
},
Worker: 3,
})
p.Run()
}
See more example.
In case to run code of synopsis. I send INT signal to golet.
Make sure to generate a struct from the New(context.Context)
function.
p := golet.New(context.Background())
Next, We can add the service using the Service
struct.
Add(services ...Service) error
method is also possible to pass multiple Service
struct arguments.
p.Add(
golet.Service{
// Replace $PORT and automatically assigned port number.
Exec: "plackup --port $PORT",
Tag: "plack", // Keyword for log.
},
golet.Service{
Exec: "echo 'This is cron!!'",
// Crontab like format.
Every: "30 * * * * *", // See https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format
Worker: 2, // Number of goroutine. The maximum number of workers is 100.
Tag: "cron",
},
)
Finally, You can run many services. use Run() error
p.Run()
The default option is like this.
interval: 0
color: false
logger: colorable.NewColorableStderr()
logWorker: true
execNotice: true
cancelSignal: -1
By using the go-colorable, colored output is also compatible with windows.
You can change these options by using the following method.
// SetInterval can specify the interval at which the command is executed.
func (c *config) SetInterval(t time.Duration) { c.interval = t }
// EnableColor can output colored log.
func (c *config) EnableColor() { c.color = true }
// SetLogger can specify the *os.File
// for example in https://github.com/lestrrat/go-file-rotatelogs
/*
logf, _ := rotatelogs.New(
"/path/to/access_log.%Y%m%d%H%M",
rotatelogs.WithLinkName("/path/to/access_log"),
rotatelogs.WithMaxAge(24 * time.Hour),
rotatelogs.WithRotationTime(time.Hour),
)
golet.New(context.Background()).SetLogger(logf)
*/
func (c *config) SetLogger(f io.Writer) { c.logger = f }
// DisableLogger is prevent to output log
func (c *config) DisableLogger() { c.logWorker = false }
// DisableExecNotice is disable execute notifications
func (c *config) DisableExecNotice() { c.execNotice = false }
// SetCtxCancelSignal can specify the signal to send processes when context cancel.
// If you do not set, golet will not send the signal when context cancel.
func (c *config) SetCtxCancelSignal(signal syscall.Signal) { c.cancelSignal = signal }
You can use temporary environment variables in golet program.
p.Env(map[string]string{
"NAME": "codehex",
"VALUE": "121",
})
and, If you execute service as command, you can get also PORT
env variable.
See, https://godoc.org/github.com/Code-Hex/golet#Context
golet.Context
can be to context.Context
, io.Writer
also io.Closer
.
So, you can try to write strange code like this.
golet.Service{
Code: func(ctx context.Context) error {
// die program
c := ctx.(*golet.Context)
fmt.Fprintf(c, "Hello, World!!\n")
c.Printf("Hello, Port: %d\n", c.Port())
time.Sleep(time.Second * 1)
select {
case <-c.Recv():
signal, err := c.Signal()
if err != nil {
c.Println(err.Error())
return err
}
switch signal {
case syscall.SIGTERM, syscall.SIGHUP:
c.Println(signal.String())
return fmt.Errorf("die message")
case syscall.SIGINT:
return nil
}
return nil
}
},
}
go get -u github.com/Code-Hex/golet
- Fork https://github.com/Code-Hex/golet/fork
- Commit your changes
- Create a new Pull Request
I'm waiting for a lot of PR.
- Create like foreman command
- Support better windows
- Write a test for signals for some distribution