wait for http server and graceful shutdown

pull/1/head
Martin Boehm 2018-01-18 17:33:20 +01:00
parent bbcadfd646
commit 4e4c17a41a
2 changed files with 59 additions and 26 deletions

View File

@ -1,11 +1,16 @@
package main
import (
"context"
"flag"
"log"
"os"
"os/signal"
"sync"
"syscall"
"time"
"blockbook/bitcoin"
"blockbook/db"
"blockbook/server"
@ -15,16 +20,16 @@ import (
type Blockchain interface {
GetBestBlockHash() (string, error)
GetBlockHash(height uint32) (string, error)
GetBlockHeader(hash string) (*BlockHeader, error)
GetBlock(hash string) (*Block, error)
GetBlockHeader(hash string) (*bitcoin.BlockHeader, error)
GetBlock(hash string) (*bitcoin.Block, error)
}
type Index interface {
GetBestBlockHash() (string, error)
GetBlockHash(height uint32) (string, error)
GetTransactions(address string, lower uint32, higher uint32, fn func(txid string) error) error
ConnectBlock(block *Block) error
DisconnectBlock(block *Block) error
ConnectBlock(block *bitcoin.Block) error
DisconnectBlock(block *bitcoin.Block) error
}
var (
@ -49,14 +54,14 @@ var (
dryRun = flag.Bool("dryrun", false, "do not index blocks, only download")
parse = flag.Bool("parse", false, "use in-process block parsing")
httpServer = flag.Bool("http", true, "run http server (default true)")
startHTTPServer = flag.Bool("httpserver", true, "run http server (default true)")
)
func main() {
flag.Parse()
if *repair {
if err := RepairRocksDB(*dbPath); err != nil {
if err := db.RepairRocksDB(*dbPath); err != nil {
log.Fatal(err)
}
return
@ -66,15 +71,15 @@ func main() {
defer profile.Start().Stop()
}
rpc := NewBitcoinRPC(
rpc := bitcoin.NewBitcoinRPC(
*rpcURL,
*rpcUser,
*rpcPass,
time.Duration(*rpcTimeout)*time.Second)
if *parse {
rpc.Parser = &BitcoinBlockParser{
Params: GetChainParams()[0],
rpc.Parser = &bitcoin.BitcoinBlockParser{
Params: bitcoin.GetChainParams()[0],
}
}
@ -84,15 +89,19 @@ func main() {
}
defer db.Close()
if *httpServer {
s, err := server.New(db)
if err != nil {
log.Fatalf("https: %s", err)
}
err = s.Run()
var httpServer *server.HttpServer
if *startHTTPServer {
httpServer, err = server.New(db)
if err != nil {
log.Fatalf("https: %s", err)
}
go func() {
err = httpServer.Run()
if err != nil {
log.Fatalf("https: %s", err)
}
}()
}
if *resync {
@ -126,6 +135,29 @@ func main() {
}
}
}
if httpServer != nil {
waitForSignalAndShutdown(httpServer, 5*time.Second)
}
}
func waitForSignalAndShutdown(s *server.HttpServer, timeout time.Duration) {
stop := make(chan os.Signal, 1)
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
<-stop
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
log.Printf("\nShutdown with timeout: %s\n", timeout)
if err := s.Shutdown(ctx); err != nil {
log.Printf("Error: %v\n", err)
} else {
log.Println("Server stopped")
}
}
func printResult(txid string) error {
@ -165,7 +197,7 @@ func resyncIndex(chain Blockchain, index Index) error {
header, err := chain.GetBlockHeader(local)
forked := false
if err != nil {
if e, ok := err.(*RPCError); ok && e.Message == "Block not found" {
if e, ok := err.(*bitcoin.RPCError); ok && e.Message == "Block not found" {
forked = true
} else {
return err
@ -310,7 +342,7 @@ func isBlockConnected(
}
type blockResult struct {
block *Block
block *bitcoin.Block
err error
}

View File

@ -2,6 +2,7 @@ package server
import (
"blockbook/db"
"context"
"encoding/json"
"fmt"
"net/http"
@ -11,16 +12,16 @@ import (
"github.com/gorilla/mux"
)
type server struct {
type HttpServer struct {
https *http.Server
db *db.RocksDB
}
func New(db *db.RocksDB) (*server, error) {
func New(db *db.RocksDB) (*HttpServer, error) {
https := &http.Server{
Addr: ":8333",
}
s := &server{
s := &HttpServer{
https: https,
db: db,
}
@ -36,22 +37,22 @@ func New(db *db.RocksDB) (*server, error) {
return s, nil
}
func (s *server) Run() error {
fmt.Printf("http server starting")
func (s *HttpServer) Run() error {
fmt.Printf("http server starting on port %s", s.https.Addr)
return s.https.ListenAndServe()
}
func (s *server) Close() error {
func (s *HttpServer) Close() error {
fmt.Printf("http server closing")
return s.https.Close()
}
func (s *server) Shutdown() error {
func (s *HttpServer) Shutdown(ctx context.Context) error {
fmt.Printf("http server shutdown")
return s.https.Shutdown()
return s.https.Shutdown(ctx)
}
func (s *server) Info(w http.ResponseWriter, r *http.Request) {
func (s *HttpServer) Info(w http.ResponseWriter, r *http.Request) {
type info struct {
Version string `json:"version"`
}