Fix sync-and-exit option logic (#628)

* fix sync-and-exit logic

* fix reading from doneSync channel

* clean up

* make statusd before using it

* move syncAndStopNode to different file

* change log level in travis chain sync command

* do not use fmt but log

* add progress log and set timeout to 20 mins

* set datadir to .ethereumtest

* fix datadir
This commit is contained in:
Adam Babik 2018-02-08 09:51:53 +01:00 committed by Dmitry Shulyak
parent d0ef64a177
commit 9885d74db0
4 changed files with 89 additions and 42 deletions

View File

@ -27,7 +27,9 @@ jobs:
# to still run, but currently does not work due to a bug
if: type != pull_request
script:
- ./build/bin/statusd -les -networkid 4 -sync-and-exit
# sync the chain first; it will time out after 20 minutes; Rinkeby is networkid=4
- make statusgo
- ./build/bin/statusd -datadir .ethereumtest/Rinkeby -les -networkid=4 -sync-and-exit=20 -log WARN -standalone=false -discovery=false
- make test-e2e networkid=4
cache:
directories:

View File

@ -114,17 +114,25 @@ func main() {
// Sync blockchain and stop.
if *syncAndExit >= 0 {
exitCode := syncAndStopNode(backend.NodeManager(), *syncAndExit)
exitCode := syncAndStopNode(interruptCh, backend.NodeManager(), *syncAndExit)
// Call was interrupted. Wait for graceful shutdown.
if exitCode == -1 {
if node, err := backend.NodeManager().Node(); err == nil && node != nil {
node.Wait()
}
return
}
// Otherwise, exit immediately with a returned exit code.
os.Exit(exitCode)
}
// wait till node has been stopped
node, err := backend.NodeManager().Node()
if err != nil {
log.Fatalf("Getting node failed: %v", err)
return
}
// wait till node has been stopped
node.Wait()
}
@ -170,34 +178,6 @@ func startCollectingStats(interruptCh <-chan struct{}, nodeManager common.NodeMa
}
}
func syncAndStopNode(nodeManager common.NodeManager, timeout int) (exitCode int) {
log.Println("Node will synchronize and exit")
if timeout < 0 {
log.Println("Sync and stop error: negative timeout value")
return 1
}
var err error
if timeout == 0 {
err = nodeManager.EnsureSync(context.Background())
} else {
ctx, cancel := context.WithTimeout(context.Background(), (time.Duration)(timeout)*time.Minute)
err = nodeManager.EnsureSync(ctx)
defer cancel()
}
if err != nil {
log.Printf("Sync error: %v", err)
exitCode = 1
}
var done <-chan struct{}
done, err = nodeManager.StopNode()
if err != nil {
log.Printf("Stop node err: %v", err)
return 1
}
<-done
return
}
// makeNodeConfig parses incoming CLI options and returns node configuration object
func makeNodeConfig() (*params.NodeConfig, error) {
devMode := !*prodMode

57
cmd/statusd/sync.go Normal file
View File

@ -0,0 +1,57 @@
package main
import (
"context"
"log"
"time"
"github.com/status-im/status-go/geth/common"
)
func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc) {
if timeout == 0 {
return context.WithCancel(context.Background())
}
return context.WithTimeout(context.Background(), time.Duration(timeout)*time.Minute)
}
// syncAndStopNode tries to sync the blockchain and stop the node.
// It returns an exit code (`0` if successful or `1` in case of error)
// that can be used in `os.Exit` to exit immediately when the function returns.
// The special exit code `-1` is used if execution was interrupted.
func syncAndStopNode(interruptCh <-chan struct{}, nodeManager common.NodeManager, timeout int) (exitCode int) {
log.Printf("syncAndStopNode: node will synchronize the chain and exit (timeout %d mins)", timeout)
ctx, cancel := createContextFromTimeout(timeout)
defer cancel()
doneSync := make(chan struct{})
errSync := make(chan error)
go func() {
if err := nodeManager.EnsureSync(ctx); err != nil {
errSync <- err
}
close(doneSync)
}()
select {
case err := <-errSync:
log.Printf("syncAndStopNode: failed to sync the chain: %v", err)
exitCode = 1
case <-doneSync:
case <-interruptCh:
// cancel context and return immediately if interrupted
// `-1` is used as a special exit code to denote interruption
return -1
}
done, err := nodeManager.StopNode()
if err != nil {
log.Printf("syncAndStopNode: failed to stop the node: %v", err)
return 1
}
<-done
return
}

View File

@ -532,25 +532,33 @@ func (m *NodeManager) EnsureSync(ctx context.Context) error {
if m.config.NetworkID == params.StatusChainNetworkID {
return nil
}
if m.lesService == nil {
return errors.New("LightEthereumService is nil")
}
return m.ensureSync(ctx)
}
func (m *NodeManager) ensureSync(ctx context.Context) error {
downloader := m.lesService.Downloader()
les, err := m.LightEthereumService()
if err != nil {
return fmt.Errorf("failed to get LES service: %v", err)
}
downloader := les.Downloader()
if downloader == nil {
return errors.New("LightEthereumService downloader is nil")
}
progress := downloader.Progress()
if progress.CurrentBlock >= progress.HighestBlock {
log.Debug("Synchronization completed")
if m.PeerCount() > 0 && progress.CurrentBlock >= progress.HighestBlock {
log.Debug("Synchronization completed", "current block", progress.CurrentBlock, "highest block", progress.HighestBlock)
return nil
}
ticker := time.NewTicker(tickerResolution)
defer ticker.Stop()
progressTicker := time.NewTicker(time.Minute)
defer progressTicker.Stop()
for {
select {
case <-ctx.Done():
@ -566,13 +574,13 @@ func (m *NodeManager) ensureSync(ctx context.Context) error {
}
progress = downloader.Progress()
if progress.CurrentBlock >= progress.HighestBlock {
log.Debug("Synchronization completed")
log.Info("Synchronization completed", "current block", progress.CurrentBlock, "highest block", progress.HighestBlock)
return nil
}
log.Debug(
fmt.Sprintf("Synchronization is not finished yet: current block %d < highest block %d",
progress.CurrentBlock, progress.HighestBlock),
)
log.Debug("Synchronization is not finished", "current", progress.CurrentBlock, "highest", progress.HighestBlock)
case <-progressTicker.C:
progress = downloader.Progress()
log.Warn("Synchronization is not finished", "current", progress.CurrentBlock, "highest", progress.HighestBlock)
}
}
}