wait for http server and graceful shutdown
This commit is contained in:
parent
bbcadfd646
commit
4e4c17a41a
66
blockbook.go
66
blockbook.go
@ -1,11 +1,16 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"blockbook/bitcoin"
|
||||||
"blockbook/db"
|
"blockbook/db"
|
||||||
"blockbook/server"
|
"blockbook/server"
|
||||||
|
|
||||||
@ -15,16 +20,16 @@ import (
|
|||||||
type Blockchain interface {
|
type Blockchain interface {
|
||||||
GetBestBlockHash() (string, error)
|
GetBestBlockHash() (string, error)
|
||||||
GetBlockHash(height uint32) (string, error)
|
GetBlockHash(height uint32) (string, error)
|
||||||
GetBlockHeader(hash string) (*BlockHeader, error)
|
GetBlockHeader(hash string) (*bitcoin.BlockHeader, error)
|
||||||
GetBlock(hash string) (*Block, error)
|
GetBlock(hash string) (*bitcoin.Block, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Index interface {
|
type Index interface {
|
||||||
GetBestBlockHash() (string, error)
|
GetBestBlockHash() (string, error)
|
||||||
GetBlockHash(height uint32) (string, error)
|
GetBlockHash(height uint32) (string, error)
|
||||||
GetTransactions(address string, lower uint32, higher uint32, fn func(txid string) error) error
|
GetTransactions(address string, lower uint32, higher uint32, fn func(txid string) error) error
|
||||||
ConnectBlock(block *Block) error
|
ConnectBlock(block *bitcoin.Block) error
|
||||||
DisconnectBlock(block *Block) error
|
DisconnectBlock(block *bitcoin.Block) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -49,14 +54,14 @@ var (
|
|||||||
dryRun = flag.Bool("dryrun", false, "do not index blocks, only download")
|
dryRun = flag.Bool("dryrun", false, "do not index blocks, only download")
|
||||||
parse = flag.Bool("parse", false, "use in-process block parsing")
|
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() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if *repair {
|
if *repair {
|
||||||
if err := RepairRocksDB(*dbPath); err != nil {
|
if err := db.RepairRocksDB(*dbPath); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -66,15 +71,15 @@ func main() {
|
|||||||
defer profile.Start().Stop()
|
defer profile.Start().Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc := NewBitcoinRPC(
|
rpc := bitcoin.NewBitcoinRPC(
|
||||||
*rpcURL,
|
*rpcURL,
|
||||||
*rpcUser,
|
*rpcUser,
|
||||||
*rpcPass,
|
*rpcPass,
|
||||||
time.Duration(*rpcTimeout)*time.Second)
|
time.Duration(*rpcTimeout)*time.Second)
|
||||||
|
|
||||||
if *parse {
|
if *parse {
|
||||||
rpc.Parser = &BitcoinBlockParser{
|
rpc.Parser = &bitcoin.BitcoinBlockParser{
|
||||||
Params: GetChainParams()[0],
|
Params: bitcoin.GetChainParams()[0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,15 +89,19 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
if *httpServer {
|
var httpServer *server.HttpServer
|
||||||
s, err := server.New(db)
|
|
||||||
if err != nil {
|
if *startHTTPServer {
|
||||||
log.Fatalf("https: %s", err)
|
httpServer, err = server.New(db)
|
||||||
}
|
|
||||||
err = s.Run()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("https: %s", err)
|
log.Fatalf("https: %s", err)
|
||||||
}
|
}
|
||||||
|
go func() {
|
||||||
|
err = httpServer.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("https: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if *resync {
|
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 {
|
func printResult(txid string) error {
|
||||||
@ -165,7 +197,7 @@ func resyncIndex(chain Blockchain, index Index) error {
|
|||||||
header, err := chain.GetBlockHeader(local)
|
header, err := chain.GetBlockHeader(local)
|
||||||
forked := false
|
forked := false
|
||||||
if err != nil {
|
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
|
forked = true
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
@ -310,7 +342,7 @@ func isBlockConnected(
|
|||||||
}
|
}
|
||||||
|
|
||||||
type blockResult struct {
|
type blockResult struct {
|
||||||
block *Block
|
block *bitcoin.Block
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"blockbook/db"
|
"blockbook/db"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -11,16 +12,16 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type server struct {
|
type HttpServer struct {
|
||||||
https *http.Server
|
https *http.Server
|
||||||
db *db.RocksDB
|
db *db.RocksDB
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(db *db.RocksDB) (*server, error) {
|
func New(db *db.RocksDB) (*HttpServer, error) {
|
||||||
https := &http.Server{
|
https := &http.Server{
|
||||||
Addr: ":8333",
|
Addr: ":8333",
|
||||||
}
|
}
|
||||||
s := &server{
|
s := &HttpServer{
|
||||||
https: https,
|
https: https,
|
||||||
db: db,
|
db: db,
|
||||||
}
|
}
|
||||||
@ -36,22 +37,22 @@ func New(db *db.RocksDB) (*server, error) {
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Run() error {
|
func (s *HttpServer) Run() error {
|
||||||
fmt.Printf("http server starting")
|
fmt.Printf("http server starting on port %s", s.https.Addr)
|
||||||
return s.https.ListenAndServe()
|
return s.https.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Close() error {
|
func (s *HttpServer) Close() error {
|
||||||
fmt.Printf("http server closing")
|
fmt.Printf("http server closing")
|
||||||
return s.https.Close()
|
return s.https.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Shutdown() error {
|
func (s *HttpServer) Shutdown(ctx context.Context) error {
|
||||||
fmt.Printf("http server shutdown")
|
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 {
|
type info struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user