Skip to content

Commit

Permalink
cmds to handle signal traps correctly #161
Browse files Browse the repository at this point in the history
The providers now have a clean up that needs to happen before the
binary exits. This is handle by trapping terminal signals and running
the clean up routines. The initial way we were doing this was not
correct.
  • Loading branch information
gdey committed Feb 14, 2018
1 parent be25743 commit 7526062
Show file tree
Hide file tree
Showing 14 changed files with 355 additions and 58 deletions.
8 changes: 4 additions & 4 deletions atlas/atlas.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (a *Atlas) AllMaps() []Map {

// SeedMapTile will generate a tile and persist it to the
// configured cache backend
func (a *Atlas) SeedMapTile(m Map, z, x, y uint64) error {
func (a *Atlas) SeedMapTile(ctx context.Context, m Map, z, x, y uint64) error {
// confirm we have a cache backend
if a.cacher == nil {
return ErrMissingCache
Expand All @@ -57,7 +57,7 @@ func (a *Atlas) SeedMapTile(m Map, z, x, y uint64) error {
tile := slippy.NewTile(z, x, y, float64(m.TileBuffer), m.SRID)

// encode the tile
b, err := m.Encode(context.Background(), tile)
b, err := m.Encode(ctx, tile)
if err != nil {
return err
}
Expand Down Expand Up @@ -159,8 +159,8 @@ func SetCache(c cache.Interface) {

// SeedMapTile will generate a tile and persist it to the
// configured cache backend for the DefaultAtlas
func SeedMapTile(m Map, z, x, y uint64) error {
return DefaultAtlas.SeedMapTile(m, z, x, y)
func SeedMapTile(ctx context.Context, m Map, z, x, y uint64) error {
return DefaultAtlas.SeedMapTile(ctx, m, z, x, y)
}

// PurgeMapTile will purge a map tile from the configured cache backend
Expand Down
39 changes: 30 additions & 9 deletions cmd/tegola/cmd/cache.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cmd

import (
"context"
"fmt"
"log"
"runtime"
"strconv"
"strings"
Expand All @@ -11,10 +11,14 @@ import (

"github.com/spf13/cobra"

gdcmd "github.com/gdey/cmd"

"github.com/terranodo/tegola"
"github.com/terranodo/tegola/atlas"
"github.com/terranodo/tegola/cache"
"github.com/terranodo/tegola/internal/log"
"github.com/terranodo/tegola/maths/webmercator"
"github.com/terranodo/tegola/provider"
)

var (
Expand Down Expand Up @@ -56,6 +60,8 @@ var cacheCmd = &cobra.Command{
return nil
},
Run: func(cmd *cobra.Command, args []string) {
defer gdcmd.New().Complete()
gdcmd.OnComplete(provider.Cleanup)
var err error
var maps []atlas.Map

Expand Down Expand Up @@ -157,8 +163,16 @@ var cacheCmd = &cobra.Command{
for i := 0; i < cacheConcurrency; i++ {
// spin off a worker listening on a channel
go func(tiler chan MapTile) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-gdcmd.Cancelled()
cancel()
}()
// range our channel to listen for jobs
for mt := range tiler {
if gdcmd.IsCancelled() {
continue
}
// we will only have a single command arg so we can switch on index 0
switch args[0] {
case "seed":
Expand Down Expand Up @@ -197,7 +211,7 @@ var cacheCmd = &cobra.Command{
}
// if we have a cache hit, then skip processing this tile
if hit {
log.Printf("cache seed set to not overwrite existing tiles. skipping map (%v) tile (%v/%v/%v)", mt.MapName, mt.Tile.Z, mt.Tile.X, mt.Tile.Y)
log.Infof("cache seed set to not overwrite existing tiles. skipping map (%v) tile (%v/%v/%v)", mt.MapName, mt.Tile.Z, mt.Tile.X, mt.Tile.Y)
continue
}
}
Expand All @@ -208,18 +222,19 @@ var cacheCmd = &cobra.Command{
}

// seed the tile
if err = atlas.SeedMapTile(m, uint64(mt.Tile.Z), uint64(mt.Tile.X), uint64(mt.Tile.Y)); err != nil {
log.Fatalf("error seeding tile (%+v): %v", mt.Tile, err)
if err = atlas.SeedMapTile(ctx, m, uint64(mt.Tile.Z), uint64(mt.Tile.X), uint64(mt.Tile.Y)); err != nil {
log.Errorf("error seeding tile (%+v): %v", mt.Tile, err)
break
}

// TODO: this is a hack to get around large arrays not being garbage collected
// https://github.com/golang/go/issues/14045 - should be addressed in Go 1.11
runtime.GC()

log.Printf("seeding map (%v) tile (%v/%v/%v) took: %v", mt.MapName, mt.Tile.Z, mt.Tile.X, mt.Tile.Y, time.Now().Sub(t))
log.Infof("seeding map (%v) tile (%v/%v/%v) took: %v", mt.MapName, mt.Tile.Z, mt.Tile.X, mt.Tile.Y, time.Now().Sub(t))

case "purge":
log.Printf("purging map (%v) tile (%v/%v/%v)", mt.MapName, mt.Tile.Z, mt.Tile.X, mt.Tile.Y)
log.Infof("purging map (%v) tile (%v/%v/%v)", mt.MapName, mt.Tile.Z, mt.Tile.X, mt.Tile.Y)

// lookup the Map
m, err := atlas.GetMap(mt.MapName)
Expand All @@ -229,7 +244,8 @@ var cacheCmd = &cobra.Command{

// purge the tile
if err = atlas.PurgeMapTile(m, mt.Tile); err != nil {
log.Fatalf("error purging tile (%+v): %v", mt.Tile, err)
log.Errorf("error purging tile (%+v): %v", mt.Tile, err)
break
}
}
}
Expand All @@ -238,8 +254,8 @@ var cacheCmd = &cobra.Command{
wg.Done()
}(tiler)
}

// iterate our zoom range
ZoomLoop:
for i := range zooms {

topLeft := *tegola.NewTileLatLong(zooms[i], bounds[1], bounds[0])
Expand All @@ -258,8 +274,13 @@ var cacheCmd = &cobra.Command{
MapName: maps[m].Name,
Tile: tegola.NewTile(zooms[i], x, y),
}
select {
case tiler <- mapTile:
case <-gdcmd.Cancelled():
log.Info("cancel recieved; cleaning up…")
break ZoomLoop
}

tiler <- mapTile
}
}
}
Expand Down
3 changes: 0 additions & 3 deletions cmd/tegola/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ func initConfig() {
log.Fatal(err)
}

// setup provider tear down.
setupTrap()

// init our providers
providers, err := initProviders(conf.Providers)
if err != nil {
Expand Down
17 changes: 16 additions & 1 deletion cmd/tegola/cmd/server.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package cmd

import (
"context"
"time"

gdcmd "github.com/gdey/cmd"
"github.com/spf13/cobra"
"github.com/terranodo/tegola/provider"
"github.com/terranodo/tegola/server"
)

Expand All @@ -15,7 +20,9 @@ var serverCmd = &cobra.Command{
Short: "Use tegola as a tile server",
Long: `Use tegola as a vector tile server. Maps tiles will be served at /maps/:map_name/:z/:x/:y`,
Run: func(cmd *cobra.Command, args []string) {
gdcmd.New()
initConfig()
gdcmd.OnComplete(provider.Cleanup)

// check config for server port setting
// if you set the port via the comand line it will override the port setting in the config
Expand All @@ -38,6 +45,14 @@ var serverCmd = &cobra.Command{
}

// start our webserver
server.Start(serverPort)
srv := server.Start(serverPort)
gdcmd.OnComplete(func() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel() // releases resources if slowOperation completes before timeout elapses
srv.Shutdown(ctx)
})
<-gdcmd.Cancelled()
gdcmd.Complete()

},
}
19 changes: 0 additions & 19 deletions cmd/tegola/cmd/trap.go

This file was deleted.

1 change: 1 addition & 0 deletions cmd/xyz2svg/cmd/draw.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ func drawCommand(cmd *cobra.Command, args []string) {
panic(err)
}
}
provider.Cleanup()
}

func drawFeatures(pname string, tiler provider.Tiler, layers []string, gid int, dfn *drawFilename) error {
Expand Down
1 change: 0 additions & 1 deletion cmd/xyz2svg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ func init() {
func initProviders(providers []map[string]interface{}) (prvs map[string]provider.Tiler, err error) {

prvs = make(map[string]provider.Tiler)
setupTrap()

// iterate providers
for _, p := range providers {
Expand Down
19 changes: 0 additions & 19 deletions cmd/xyz2svg/cmd/trap.go

This file was deleted.

2 changes: 2 additions & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/terranodo/tegola/geom"
"github.com/terranodo/tegola/internal/log"
)

type Tile interface {
Expand Down Expand Up @@ -91,6 +92,7 @@ func For(name string, config map[string]interface{}) (Tiler, error) {
}

func Cleanup() {
log.Info("cleaning up providers")
for _, p := range providers {
if p.cleanup != nil {
p.cleanup()
Expand Down
6 changes: 4 additions & 2 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var (
)

// Start starts the tile server binding to the provided port
func Start(port string) {
func Start(port string) *http.Server {
Atlas = atlas.DefaultAtlas

// notify the user the server is starting
Expand Down Expand Up @@ -64,7 +64,9 @@ func Start(port string) {
group.UsingContext().Handler("GET", "/*path", http.FileServer(assetFS()))

// start our server
log.Fatal(http.ListenAndServe(port, r))
srv := &http.Server{Addr: port, Handler: r}
go func() { log.Error(srv.ListenAndServe()) }()
return srv
}

// determines the hostname:port to return based on the following hierarchy
Expand Down
21 changes: 21 additions & 0 deletions vendor/github.com/gdey/cmd/LICENSE.md

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

45 changes: 45 additions & 0 deletions vendor/github.com/gdey/cmd/README.md

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

Loading

0 comments on commit 7526062

Please sign in to comment.