Files
gotenberg/internal/pkg/prinery/prinery.go
2019-09-19 17:28:29 +02:00

124 lines
2.6 KiB
Go

package prinery
import (
"context"
"fmt"
"github.com/thecodingmachine/gotenberg/internal/pkg/print"
"github.com/thecodingmachine/gotenberg/internal/pkg/process"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
"github.com/thecodingmachine/gotenberg/internal/pkg/xlog"
)
type request struct {
ctx context.Context
logger xlog.Logger
print print.Print
dest string
result chan error
}
type worker struct {
work chan request
proc process.Process
}
func (w *worker) do(done chan *worker) {
for {
req := <-w.work
req.result <- req.print.Print(req.ctx, req.dest, w.proc)
done <- w
}
}
type Prinery struct {
logger xlog.Logger
manager process.Manager
work chan request
pool chan *worker
done chan *worker
}
func New(logger xlog.Logger, manager process.Manager, key process.Key) (*Prinery, error) {
const op string = "prinery.New"
processes := manager.Processes(key)
nWorkers := len(processes)
if nWorkers == 0 {
err := fmt.Errorf("no processes found for key '%s'", string(key))
return nil, xerror.New(op, err)
}
logger.DebugfOp(op, "found '%d' processes for key '%s'", nWorkers, string(key))
work := make(chan request, 1)
pool := make(chan *worker, nWorkers)
done := make(chan *worker, nWorkers)
for _, p := range processes {
w := &worker{
work: work,
proc: p,
}
pool <- w
go w.do(done)
}
return &Prinery{
logger: logger,
manager: manager,
work: work,
pool: pool,
done: done,
}, nil
}
func (p *Prinery) PrintRequest(ctx context.Context, logger xlog.Logger, prnt print.Print, dest string) error {
const op string = "prinery.Prinery.PrintRequest"
req := request{
ctx: ctx,
logger: logger,
print: prnt,
dest: dest,
result: make(chan error),
}
p.dispatch(req)
err := <-req.result
if err != nil {
return xerror.New(op, err)
}
return nil
}
func (p *Prinery) Start() {
for {
select {
case req := <-p.work:
p.dispatch(req)
case w := <-p.done:
p.completed(w)
}
}
}
func (p *Prinery) dispatch(req request) {
const op string = "prinery.Prinery.dispatch"
select {
case w := <-p.pool:
w.work <- req
case <-req.ctx.Done():
req.result <- xerror.New(op, req.ctx.Err())
}
}
func (p *Prinery) completed(w *worker) {
const op string = "prinery.Prinerty.completed"
go func() {
// check process viability.
isViable := p.manager.IsViable(w.proc)
// check process memory usage.
// TODO handle error.
memory, _ := p.manager.Memory(w.proc)
p.logger.DebugfOp(op, "%s: isViable = %t, memory = %d", w.proc.ID(), isViable, memory)
// TODO manage viability and memory usage.
// pushing back the worker.
p.pool <- w
}()
}