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:
parent
d0ef64a177
commit
9885d74db0
|
@ -27,7 +27,9 @@ jobs:
|
||||||
# to still run, but currently does not work due to a bug
|
# to still run, but currently does not work due to a bug
|
||||||
if: type != pull_request
|
if: type != pull_request
|
||||||
script:
|
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
|
- make test-e2e networkid=4
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
|
|
|
@ -114,17 +114,25 @@ func main() {
|
||||||
|
|
||||||
// Sync blockchain and stop.
|
// Sync blockchain and stop.
|
||||||
if *syncAndExit >= 0 {
|
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)
|
os.Exit(exitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait till node has been stopped
|
|
||||||
node, err := backend.NodeManager().Node()
|
node, err := backend.NodeManager().Node()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Getting node failed: %v", err)
|
log.Fatalf("Getting node failed: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wait till node has been stopped
|
||||||
node.Wait()
|
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
|
// makeNodeConfig parses incoming CLI options and returns node configuration object
|
||||||
func makeNodeConfig() (*params.NodeConfig, error) {
|
func makeNodeConfig() (*params.NodeConfig, error) {
|
||||||
devMode := !*prodMode
|
devMode := !*prodMode
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -532,25 +532,33 @@ func (m *NodeManager) EnsureSync(ctx context.Context) error {
|
||||||
if m.config.NetworkID == params.StatusChainNetworkID {
|
if m.config.NetworkID == params.StatusChainNetworkID {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if m.lesService == nil {
|
|
||||||
return errors.New("LightEthereumService is nil")
|
|
||||||
}
|
|
||||||
return m.ensureSync(ctx)
|
return m.ensureSync(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *NodeManager) ensureSync(ctx context.Context) error {
|
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 {
|
if downloader == nil {
|
||||||
return errors.New("LightEthereumService downloader is nil")
|
return errors.New("LightEthereumService downloader is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
progress := downloader.Progress()
|
progress := downloader.Progress()
|
||||||
if progress.CurrentBlock >= progress.HighestBlock {
|
if m.PeerCount() > 0 && progress.CurrentBlock >= progress.HighestBlock {
|
||||||
log.Debug("Synchronization completed")
|
log.Debug("Synchronization completed", "current block", progress.CurrentBlock, "highest block", progress.HighestBlock)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(tickerResolution)
|
ticker := time.NewTicker(tickerResolution)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
progressTicker := time.NewTicker(time.Minute)
|
||||||
|
defer progressTicker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -566,13 +574,13 @@ func (m *NodeManager) ensureSync(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
progress = downloader.Progress()
|
progress = downloader.Progress()
|
||||||
if progress.CurrentBlock >= progress.HighestBlock {
|
if progress.CurrentBlock >= progress.HighestBlock {
|
||||||
log.Debug("Synchronization completed")
|
log.Info("Synchronization completed", "current block", progress.CurrentBlock, "highest block", progress.HighestBlock)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Debug(
|
log.Debug("Synchronization is not finished", "current", progress.CurrentBlock, "highest", progress.HighestBlock)
|
||||||
fmt.Sprintf("Synchronization is not finished yet: current block %d < highest block %d",
|
case <-progressTicker.C:
|
||||||
progress.CurrentBlock, progress.HighestBlock),
|
progress = downloader.Progress()
|
||||||
)
|
log.Warn("Synchronization is not finished", "current", progress.CurrentBlock, "highest", progress.HighestBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue