geth: better error notification

This commit is contained in:
Victor Farazdagi 2017-01-12 20:56:36 +03:00
parent 1cc8259589
commit 26841d91e7
6 changed files with 59 additions and 5 deletions

View File

@ -1101,6 +1101,11 @@ func startTestNode(t *testing.T) <-chan struct{} {
t.Errorf("cannot unmarshal event's JSON: %s", jsonEvent)
return
}
if envelope.Type == geth.EventNodeCrashed {
geth.TriggerDefaultNodeNotificationHandler(jsonEvent)
return
}
if envelope.Type == geth.EventTransactionQueued {
}
if envelope.Type == geth.EventNodeStarted {

View File

@ -9,6 +9,7 @@ import (
"path/filepath"
"reflect"
"runtime"
"runtime/debug"
"strings"
"syscall"
@ -43,6 +44,7 @@ const (
DatabaseCacheSize = 128 // Megabytes of memory allocated to internal caching (min 16MB / database forced)
EventNodeStarted = "node.started"
EventNodeCrashed = "node.crashed"
)
// Gas price settings
@ -313,5 +315,24 @@ func Fatalf(reason interface{}, args ...interface{}) {
fmt.Fprintf(w, "Fatal Failure: %v\n", reason.(error))
}
debug.PrintStack()
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
}
}

View File

@ -67,6 +67,8 @@ var (
// CreateAndRunNode creates and starts running Geth node locally (exposing given RPC port along the way)
func CreateAndRunNode(dataDir string, rpcPort int) error {
defer HaltOnPanic()
nodeManager := NewNodeManager(dataDir, rpcPort)
if nodeManager.NodeInited() {
@ -101,6 +103,8 @@ func NodeManagerInstance() *NodeManager {
// RunNode starts Geth node
func (m *NodeManager) RunNode() {
go func() {
defer HaltOnPanic()
m.StartNode()
if _, err := m.AccountManager(); err != nil {

View File

@ -1,6 +1,8 @@
package geth_test
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
@ -37,6 +39,15 @@ func TestMain(m *testing.M) {
}
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":{}}` {
signalRecieved <- struct{}{}
}

View File

@ -21,6 +21,10 @@ type JSONError struct {
Error string `json:"error"`
}
type NodeCrashEvent struct {
Error string `json:"error"`
}
type AddPeerResult struct {
Success bool `json:"success"`
Error string `json:"error"`

View File

@ -31,15 +31,19 @@ const (
type NodeNotificationHandler func(jsonEvent string)
var notificationHandler NodeNotificationHandler = func(jsonEvent string) { // internal signal handler (used in tests)
glog.V(logger.Info).Infof("notification received (default notification handler): %s\n", jsonEvent)
}
var notificationHandler NodeNotificationHandler = TriggerDefaultNodeNotificationHandler
// SetDefaultNodeNotificationHandler sets notification handler to invoke on SendSignal
func SetDefaultNodeNotificationHandler(fn NodeNotificationHandler) {
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) {
data, _ := json.Marshal(&signal)
C.StatusServiceSignalEvent(C.CString(string(data)))
@ -98,6 +102,8 @@ func PrepareTestNode() (err error) {
return nil
}
defer HaltOnPanic()
syncRequired := false
if _, err := os.Stat(filepath.Join(TestDataDir, "testnet")); os.IsNotExist(err) {
syncRequired = true
@ -122,7 +128,10 @@ func PrepareTestNode() (err error) {
// start geth node and wait for it to initialize
// 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()
if !manager.NodeInited() {