geth: better error notification
This commit is contained in:
parent
1cc8259589
commit
26841d91e7
|
@ -1101,6 +1101,11 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
||||||
t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent)
|
t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if envelope.Type == geth.EventNodeCrashed {
|
||||||
|
geth.TriggerDefaultNodeNotificationHandler(jsonEvent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if envelope.Type == geth.EventTransactionQueued {
|
if envelope.Type == geth.EventTransactionQueued {
|
||||||
}
|
}
|
||||||
if envelope.Type == geth.EventNodeStarted {
|
if envelope.Type == geth.EventNodeStarted {
|
||||||
|
|
21
geth/node.go
21
geth/node.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ const (
|
||||||
DatabaseCacheSize = 128 // Megabytes of memory allocated to internal caching (min 16MB / database forced)
|
DatabaseCacheSize = 128 // Megabytes of memory allocated to internal caching (min 16MB / database forced)
|
||||||
|
|
||||||
EventNodeStarted = "node.started"
|
EventNodeStarted = "node.started"
|
||||||
|
EventNodeCrashed = "node.crashed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gas price settings
|
// Gas price settings
|
||||||
|
@ -313,5 +315,24 @@ func Fatalf(reason interface{}, args ...interface{}) {
|
||||||
fmt.Fprintf(w, "Fatal Failure: %v\n", reason.(error))
|
fmt.Fprintf(w, "Fatal Failure: %v\n", reason.(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug.PrintStack()
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HaltOnPanic recovers from panic, logs issue, sends upward notification, and exits
|
||||||
|
func HaltOnPanic() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err := fmt.Errorf("%v: %v", ErrNodeStartFailure, r)
|
||||||
|
|
||||||
|
// send signal up to native app
|
||||||
|
SendSignal(SignalEnvelope{
|
||||||
|
Type: EventNodeCrashed,
|
||||||
|
Event: NodeCrashEvent{
|
||||||
|
Error: err.Error(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
Fatalf(err) // os.exit(1) is called internally
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ var (
|
||||||
|
|
||||||
// CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way)
|
// CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way)
|
||||||
func CreateAndRunNode(dataDir string, rpcPort int) error {
|
func CreateAndRunNode(dataDir string, rpcPort int) error {
|
||||||
|
defer HaltOnPanic()
|
||||||
|
|
||||||
nodeManager := NewNodeManager(dataDir, rpcPort)
|
nodeManager := NewNodeManager(dataDir, rpcPort)
|
||||||
|
|
||||||
if nodeManager.NodeInited() {
|
if nodeManager.NodeInited() {
|
||||||
|
@ -101,6 +103,8 @@ func NodeManagerInstance() *NodeManager {
|
||||||
// RunNode starts Geth node
|
// RunNode starts Geth node
|
||||||
func (m *NodeManager) RunNode() {
|
func (m *NodeManager) RunNode() {
|
||||||
go func() {
|
go func() {
|
||||||
|
defer HaltOnPanic()
|
||||||
|
|
||||||
m.StartNode()
|
m.StartNode()
|
||||||
|
|
||||||
if _, err := m.AccountManager(); err != nil {
|
if _, err := m.AccountManager(); err != nil {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package geth_test
|
package geth_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -37,6 +39,15 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
|
|
||||||
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
||||||
|
var envelope geth.SignalEnvelope
|
||||||
|
if err := json.Unmarshal([]byte(jsonEvent), &envelope); err != nil {
|
||||||
|
panic(fmt.Errorf("cannot unmarshal event's JSON: %s", jsonEvent))
|
||||||
|
}
|
||||||
|
if envelope.Type == geth.EventNodeCrashed {
|
||||||
|
geth.TriggerDefaultNodeNotificationHandler(jsonEvent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if jsonEvent == `{"type":"node.started","event":{}}` {
|
if jsonEvent == `{"type":"node.started","event":{}}` {
|
||||||
signalRecieved <- struct{}{}
|
signalRecieved <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ type JSONError struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeCrashEvent struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
type AddPeerResult struct {
|
type AddPeerResult struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
|
|
|
@ -31,15 +31,19 @@ const (
|
||||||
|
|
||||||
type NodeNotificationHandler func(jsonEvent string)
|
type NodeNotificationHandler func(jsonEvent string)
|
||||||
|
|
||||||
var notificationHandler NodeNotificationHandler = func(jsonEvent string) { // internal signal handler (used in tests)
|
var notificationHandler NodeNotificationHandler = TriggerDefaultNodeNotificationHandler
|
||||||
glog.V(logger.Info).Infof("notification received (default notification handler): %s\n", jsonEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// SetDefaultNodeNotificationHandler sets notification handler to invoke on SendSignal
|
||||||
func SetDefaultNodeNotificationHandler(fn NodeNotificationHandler) {
|
func SetDefaultNodeNotificationHandler(fn NodeNotificationHandler) {
|
||||||
notificationHandler = fn
|
notificationHandler = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendSignal sends application signal (JSON, normally) upwards
|
// TriggerDefaultNodeNotificationHandler triggers default notification handler (helpful in tests)
|
||||||
|
func TriggerDefaultNodeNotificationHandler(jsonEvent string) {
|
||||||
|
glog.V(logger.Info).Infof("notification received (default notification handler): %s\n", jsonEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendSignal sends application signal (JSON, normally) upwards to application (via default notification handler)
|
||||||
func SendSignal(signal SignalEnvelope) {
|
func SendSignal(signal SignalEnvelope) {
|
||||||
data, _ := json.Marshal(&signal)
|
data, _ := json.Marshal(&signal)
|
||||||
C.StatusServiceSignalEvent(C.CString(string(data)))
|
C.StatusServiceSignalEvent(C.CString(string(data)))
|
||||||
|
@ -98,6 +102,8 @@ func PrepareTestNode() (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer HaltOnPanic()
|
||||||
|
|
||||||
syncRequired := false
|
syncRequired := false
|
||||||
if _, err := os.Stat(filepath.Join(TestDataDir, "testnet")); os.IsNotExist(err) {
|
if _, err := os.Stat(filepath.Join(TestDataDir, "testnet")); os.IsNotExist(err) {
|
||||||
syncRequired = true
|
syncRequired = true
|
||||||
|
@ -122,7 +128,10 @@ func PrepareTestNode() (err error) {
|
||||||
|
|
||||||
// start geth node and wait for it to initialize
|
// start geth node and wait for it to initialize
|
||||||
// internally once.Do() is used, so call below is thread-safe
|
// internally once.Do() is used, so call below is thread-safe
|
||||||
CreateAndRunNode(dataDir, 8546) // to avoid conflicts with running react-native app, run on different port
|
err = CreateAndRunNode(dataDir, 8546) // to avoid conflicts with running react-native app, run on different port
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
manager = NodeManagerInstance()
|
manager = NodeManagerInstance()
|
||||||
if !manager.NodeInited() {
|
if !manager.NodeInited() {
|
||||||
|
|
Loading…
Reference in New Issue