added shutdownevent for graceful shutdown
diff --git a/apid.go b/apid.go
index 73f243c..7da00d9 100644
--- a/apid.go
+++ b/apid.go
@@ -1,9 +1,12 @@
package apid
-import "os"
+import (
+ "os"
+)
const (
SystemEventsSelector EventSelector = "system event"
+ ShutdownEventSelector EventSelector = "shutdown event"
)
var (
@@ -12,6 +15,8 @@
pluginInitFuncs []PluginInitFunc
services Services
+
+ shutdownChan chan int
)
type Services interface {
@@ -44,6 +49,8 @@
ss.api = s.API()
ss.data = s.Data()
+ shutdownChan = make(chan int)
+
ss.events.Emit(SystemEventsSelector, APIDInitializedEvent)
}
@@ -69,6 +76,24 @@
log.Debugf("done initializing plugins")
}
+func ShutdownPlugins() {
+ Events().EmitWithCallback(ShutdownEventSelector, ShutdownEvent{"apid is going to shutdown"}, ShutdownHandler)
+}
+
+
+func ShutdownHandler(event Event) {
+ log := Log()
+ log.Debugf("shutdown apid")
+ shutdownChan <- 1
+}
+
+/* wait for the shutdown of registered graceful-shutdown plugins, blocking until the required plugins finish shutdown
+ * this is used to prevent the main from exiting
+ */
+func WaitPluginsShutdown() {
+ <- shutdownChan
+}
+
func AllServices() Services {
return services
}
@@ -124,3 +149,7 @@
type systemEvent struct {
description string
}
+
+type ShutdownEvent struct {
+ Description string
+}
diff --git a/events/event_manager.go b/events/event_manager.go
index 33b0ee1..12e8f82 100644
--- a/events/event_manager.go
+++ b/events/event_manager.go
@@ -13,7 +13,8 @@
func (em *eventManager) Emit(selector apid.EventSelector, event apid.Event) {
log.Debugf("emit selector: '%s' event %v: %v", selector, &event, event)
- if !em.dispatchers[selector].Send(event) {
+ eventDispatcher := em.dispatchers[selector]
+ if (eventDispatcher==nil) || (!eventDispatcher.Send(event)) {
em.sendDelivered(selector, event, 0) // in case of no dispatcher
}
}
diff --git a/events/events_test.go b/events/events_test.go
index 70bc19a..b2e3f9d 100644
--- a/events/events_test.go
+++ b/events/events_test.go
@@ -6,6 +6,8 @@
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"sync/atomic"
+ "fmt"
+ "strconv"
)
var _ = Describe("Events Service", func() {
@@ -287,8 +289,75 @@
apid.InitializePlugins()
})
+ It("shutdown event should be emitted and listened successfully", func(done Done) {
+ h := func(event apid.Event) {
+ defer GinkgoRecover()
+
+ if pie, ok := event.(apid.ShutdownEvent); ok {
+ apid.Events().Close()
+ Expect(pie.Description).Should(Equal("apid is going to shutdown"))
+ fmt.Println(pie.Description)
+ close(done)
+ } else {
+ Fail("Received wrong event")
+ }
+ }
+ apid.Events().ListenFunc(apid.ShutdownEventSelector, h)
+ shutdownHandler := func(event apid.Event) {}
+ apid.Events().EmitWithCallback(apid.ShutdownEventSelector, apid.ShutdownEvent{"apid is going to shutdown"}, shutdownHandler)
+ })
+
+ It("handlers registered by plugins should execute before apid shutdown", func(done Done) {
+ pluginNum := 10
+ count := make([]int, 1)
+ count[0] = 0
+
+ // create and register plugins, listen to shutdown event
+ for i:=0; i<pluginNum; i++ {
+ apid.RegisterPlugin(createDummyPlugin(i))
+ h := func(event apid.Event) {
+ if pie, ok := event.(apid.ShutdownEvent); ok {
+ Expect(pie.Description).Should(Equal("apid is going to shutdown"))
+ count[0] += 1
+ } else {
+ Fail("Received wrong event")
+ }
+ }
+ apid.Events().ListenFunc(apid.ShutdownEventSelector, h)
+ }
+
+
+ apid.InitializePlugins()
+
+ apid.ShutdownPlugins()
+
+ apid.WaitPluginsShutdown()
+
+ defer GinkgoRecover()
+ apid.Events().Close()
+ // handlers of all registered plugins have executed
+ Expect(count[0]).Should(Equal(pluginNum))
+ fmt.Println("handlers of all registered plugins have executed")
+
+ close(done)
+ })
})
+func createDummyPlugin(id int) apid.PluginInitFunc{
+ xData := make(map[string]interface{})
+ xData["schemaVersion"] = "1.2.3"
+ p := func(s apid.Services) (pd apid.PluginData, err error) {
+ pd = apid.PluginData{
+ Name: "test plugin " + strconv.Itoa(id),
+ Version: "1.0.0",
+ ExtraData: xData,
+ }
+ return
+ }
+ return p
+
+}
+
type test_handler struct {
description string
f func(event apid.Event)