mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-16 20:32:13 +01:00
adds configurable debugging of startup of processes and print out some info from the chrome viable() function for debugging purposes
This commit is contained in:
@@ -25,6 +25,7 @@ const (
|
|||||||
disableGoogleChromeEnvVar = "DISABLE_GOOGLE_CHROME"
|
disableGoogleChromeEnvVar = "DISABLE_GOOGLE_CHROME"
|
||||||
disableUnoconvEnvVar = "DISABLE_UNOCONV"
|
disableUnoconvEnvVar = "DISABLE_UNOCONV"
|
||||||
disableHealthcheckLoggingEnvVar = "DISABLE_HEALTHCHECK_LOGGING"
|
disableHealthcheckLoggingEnvVar = "DISABLE_HEALTHCHECK_LOGGING"
|
||||||
|
debugProcessStartup = "DEBUG_PROCESS_STARTUP"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustParseEnvVar() *api.Options {
|
func mustParseEnvVar() *api.Options {
|
||||||
@@ -49,37 +50,31 @@ func mustParseEnvVar() *api.Options {
|
|||||||
}
|
}
|
||||||
opts.DefaultListenPort = v
|
opts.DefaultListenPort = v
|
||||||
}
|
}
|
||||||
if v, ok := os.LookupEnv(disableGoogleChromeEnvVar); ok {
|
//checkBoolEnv is a convenience function for reading an env var with a bool value where `1` is true and `0` is false
|
||||||
if v != "1" && v != "0" {
|
checkBoolEnv := func(name string) bool {
|
||||||
notify.ErrPrint(fmt.Errorf("%s: wrong value: want \"0\" or \"1\" got %v", disableGoogleChromeEnvVar, v))
|
if v, ok := os.LookupEnv(name); ok {
|
||||||
os.Exit(1)
|
if v != "1" && v != "0" {
|
||||||
|
notify.ErrPrint(fmt.Errorf("%s: wrong value: want \"0\" or \"1\" got %v", name, v))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return v == "1"
|
||||||
}
|
}
|
||||||
opts.EnableChromeEndpoints = v != "1"
|
return false
|
||||||
}
|
|
||||||
if v, ok := os.LookupEnv(disableUnoconvEnvVar); ok {
|
|
||||||
if v != "1" && v != "0" {
|
|
||||||
notify.ErrPrint(fmt.Errorf("%s: wrong value: want \"0\" or \"1\" got %v", disableUnoconvEnvVar, v))
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
opts.EnableUnoconvEndpoints = v != "1"
|
|
||||||
}
|
|
||||||
if v, ok := os.LookupEnv(disableHealthcheckLoggingEnvVar); ok {
|
|
||||||
if v != "1" && v != "0" {
|
|
||||||
notify.ErrPrint(fmt.Errorf("%s: wrong value: want \"0\" or \"1\" got %v", disableHealthcheckLoggingEnvVar, v))
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
opts.EnableHealthcheckLogging = v != "1"
|
|
||||||
}
|
}
|
||||||
|
opts.EnableChromeEndpoints = !checkBoolEnv(disableGoogleChromeEnvVar)
|
||||||
|
opts.EnableUnoconvEndpoints = !checkBoolEnv(disableUnoconvEnvVar)
|
||||||
|
opts.EnableHealthcheckLogging = !checkBoolEnv(disableHealthcheckLoggingEnvVar)
|
||||||
|
opts.DebugProcessStartup = checkBoolEnv(debugProcessStartup)
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustStartProcesses(opts *api.Options) []pm2.Process {
|
func mustStartProcesses(opts *api.Options) []pm2.Process {
|
||||||
var processes []pm2.Process
|
var processes []pm2.Process
|
||||||
if opts.EnableChromeEndpoints {
|
if opts.EnableChromeEndpoints {
|
||||||
processes = append(processes, pm2.NewChrome())
|
processes = append(processes, pm2.NewChrome(opts.DebugProcessStartup))
|
||||||
}
|
}
|
||||||
if opts.EnableUnoconvEndpoints {
|
if opts.EnableUnoconvEndpoints {
|
||||||
processes = append(processes, pm2.NewUnoconv())
|
processes = append(processes, pm2.NewUnoconv(opts.DebugProcessStartup))
|
||||||
}
|
}
|
||||||
for _, p := range processes {
|
for _, p := range processes {
|
||||||
notify.Printf("starting %s with PM2...", p.Fullname())
|
notify.Printf("starting %s with PM2...", p.Fullname())
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import "github.com/labstack/echo/v4"
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
const pingEndpoint = "/ping"
|
const pingEndpoint = "/ping"
|
||||||
|
|
||||||
@@ -14,6 +12,7 @@ type Options struct {
|
|||||||
EnableChromeEndpoints bool
|
EnableChromeEndpoints bool
|
||||||
EnableUnoconvEndpoints bool
|
EnableUnoconvEndpoints bool
|
||||||
EnableHealthcheckLogging bool
|
EnableHealthcheckLogging bool
|
||||||
|
DebugProcessStartup bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultOptions returns default options.
|
// DefaultOptions returns default options.
|
||||||
|
|||||||
@@ -7,15 +7,19 @@ import (
|
|||||||
"github.com/mafredri/cdp/devtool"
|
"github.com/mafredri/cdp/devtool"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
warmupTime = 10 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
type chrome struct {
|
type chrome struct {
|
||||||
manager *processManager
|
manager *processManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChrome retruns a Google Chrome
|
// NewChrome retruns a Google Chrome
|
||||||
// headless process.
|
// headless process.
|
||||||
func NewChrome() Process {
|
func NewChrome(debug bool) Process {
|
||||||
return &chrome{
|
return &chrome{
|
||||||
manager: &processManager{},
|
manager: &processManager{verbose: debug},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,12 +62,20 @@ func (p *chrome) viable() bool {
|
|||||||
// check if Google Chrome is correctly running.
|
// check if Google Chrome is correctly running.
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
_, err := devtool.New("http://localhost:9222").Version(ctx)
|
p.manager.notifyf(`%v: checking Chrome liveness via debug version endpoint
|
||||||
return err == nil
|
'http://localhost:9222/json/version'`, p.name())
|
||||||
|
v, err := devtool.New("http://localhost:9222").Version(ctx)
|
||||||
|
if err != nil {
|
||||||
|
p.manager.notifyf("%v: Chrome version endpoint returned error: %v", p.name(), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.manager.notifyf("%v: Chrome returned version info: %+v", p.name(), *v)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *chrome) warmup() {
|
func (p *chrome) warmup() {
|
||||||
time.Sleep(5 * time.Second)
|
p.manager.notifyf("%v: allowing Chrome %v to startup", p.name(), warmupTime)
|
||||||
|
time.Sleep(warmupTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile-time checks to ensure type implements desired interfaces.
|
// Compile-time checks to ensure type implements desired interfaces.
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestChromeStart(t *testing.T) {
|
func TestChromeStart(t *testing.T) {
|
||||||
p := NewChrome()
|
p := NewChrome(false)
|
||||||
err := p.Start()
|
err := p.Start()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChromeShutdown(t *testing.T) {
|
func TestChromeShutdown(t *testing.T) {
|
||||||
p := NewChrome()
|
p := NewChrome(false)
|
||||||
err := p.Shutdown()
|
err := p.Shutdown()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
package pm2
|
package pm2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/thecodingmachine/gotenberg/internal/pkg/notify"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -25,6 +31,7 @@ type Process interface {
|
|||||||
|
|
||||||
type processManager struct {
|
type processManager struct {
|
||||||
heuristicState int32
|
heuristicState int32
|
||||||
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *processManager) start(p Process) error {
|
func (m *processManager) start(p Process) error {
|
||||||
@@ -76,8 +83,43 @@ func (m *processManager) pm2(p Process, cmdName string) error {
|
|||||||
"pm2",
|
"pm2",
|
||||||
cmdArgs...,
|
cmdArgs...,
|
||||||
)
|
)
|
||||||
|
m.notifyf("executing command '%v'", strings.Join(cmd.Args, " "))
|
||||||
|
if m.verbose {
|
||||||
|
chromeStdErr, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed getting Chrome stderr: %v", err)
|
||||||
|
}
|
||||||
|
chromeStdOut, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed getting Chrome stdout: %v", err)
|
||||||
|
}
|
||||||
|
readFromPipe := func(name string, reader io.ReadCloser) {
|
||||||
|
r := bufio.NewReader(reader)
|
||||||
|
defer reader.Close()
|
||||||
|
for {
|
||||||
|
line, _, err := r.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
m.notifyf("error reading from %v for process %v", name, p.name())
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(line) != 0 {
|
||||||
|
m.notifyf("%v %v: %s", p.name(), name, string(line))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go readFromPipe("stdout", chromeStdOut)
|
||||||
|
go readFromPipe("stderr", chromeStdErr)
|
||||||
|
}
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return fmt.Errorf("%s %s with PM2: %v", cmdName, p.Fullname(), err)
|
return fmt.Errorf("%s %s with PM2: %v", cmdName, p.Fullname(), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *processManager) notifyf(format string, args ...interface{}) {
|
||||||
|
if m.verbose {
|
||||||
|
notify.Printf(fmt.Sprintf("%v: %s", time.Now().Format(time.RFC3339), format), args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ type unoconv struct {
|
|||||||
|
|
||||||
// NewUnoconv retruns a unoconv listener
|
// NewUnoconv retruns a unoconv listener
|
||||||
// process.
|
// process.
|
||||||
func NewUnoconv() Process {
|
func NewUnoconv(debug bool) Process {
|
||||||
return &unoconv{
|
return &unoconv{
|
||||||
manager: &processManager{},
|
manager: &processManager{verbose: debug},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestUnoconvStart(t *testing.T) {
|
func TestUnoconvStart(t *testing.T) {
|
||||||
p := NewUnoconv()
|
p := NewUnoconv(false)
|
||||||
err := p.Start()
|
err := p.Start()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnoconvShutdown(t *testing.T) {
|
func TestUnoconvShutdown(t *testing.T) {
|
||||||
p := NewUnoconv()
|
p := NewUnoconv(false)
|
||||||
err := p.Shutdown()
|
err := p.Shutdown()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user