From c0fc4fc0cb67bab34ec8455ae8c1726a597acadd Mon Sep 17 00:00:00 2001
From: Luca Moser <moser.luca@gmail.com>
Date: Wed, 15 Jan 2020 10:43:38 +0100
Subject: [PATCH] makes shutdown routines cleaner (#115)

Signed-off-by: Luca Moser <moser.luca@gmail.com>
---
 packages/shutdown/order.go                    | 18 +++++++++++++++
 .../transactionspammer/transactionspammer.go  |  3 ++-
 plugins/analysis/client/plugin.go             |  3 ++-
 plugins/analysis/server/plugin.go             |  3 ++-
 .../webinterface/httpserver/plugin.go         |  3 ++-
 plugins/autopeering/plugin.go                 |  3 ++-
 plugins/bundleprocessor/plugin.go             |  5 +++--
 plugins/dashboard/plugin.go                   |  3 ++-
 plugins/gossip/plugin.go                      |  3 ++-
 plugins/graph/plugin.go                       |  5 +++--
 plugins/metrics/plugin.go                     |  3 ++-
 plugins/statusscreen-tps/plugin.go            |  3 ++-
 plugins/statusscreen/plugin.go                |  5 +++--
 plugins/tangle/approvers.go                   | 22 ++++++++++++-------
 plugins/tangle/bundle.go                      | 22 ++++++++++++-------
 plugins/tangle/plugin.go                      | 19 ++++++++++++++++
 plugins/tangle/solidifier.go                  |  3 ++-
 plugins/tangle/transaction.go                 | 22 ++++++++++++-------
 plugins/tangle/transaction_metadata.go        | 22 ++++++++++++-------
 plugins/ui/ui.go                              |  3 ++-
 plugins/webapi/plugin.go                      |  3 ++-
 plugins/webauth/webauth.go                    |  3 ++-
 plugins/zeromq/plugin.go                      |  3 ++-
 23 files changed, 130 insertions(+), 52 deletions(-)
 create mode 100644 packages/shutdown/order.go

diff --git a/packages/shutdown/order.go b/packages/shutdown/order.go
new file mode 100644
index 00000000..b16bc91e
--- /dev/null
+++ b/packages/shutdown/order.go
@@ -0,0 +1,18 @@
+package shutdown
+
+const (
+	ShutdownPriorityTangle = iota
+	ShutdownPrioritySolidifier
+	ShutdownPriorityBundleProcessor
+	ShutdownPriorityAnalysis
+	ShutdownPriorityMetrics
+	ShutdownPriorityWebAPI
+	ShutdownPriorityGossip
+	ShutdownPriorityZMQ
+	ShutdownPriorityAutopeering
+	ShutdownPriorityGraph
+	ShutdownPriorityUI
+	ShutdownPriorityDashboard
+	ShutdownPriorityTangleSpammer
+	ShutdownPriorityStatusScreen
+)
diff --git a/packages/transactionspammer/transactionspammer.go b/packages/transactionspammer/transactionspammer.go
index a2cae4ae..dcfb1da1 100644
--- a/packages/transactionspammer/transactionspammer.go
+++ b/packages/transactionspammer/transactionspammer.go
@@ -4,6 +4,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
 
 	"github.com/iotaledger/goshimmer/packages/gossip"
@@ -79,7 +80,7 @@ func Start(tps uint) {
 				}
 			}
 		}
-	})
+	}, shutdown.ShutdownPriorityTangleSpammer)
 }
 
 func Stop() {
diff --git a/plugins/analysis/client/plugin.go b/plugins/analysis/client/plugin.go
index 50698234..ccec3955 100644
--- a/plugins/analysis/client/plugin.go
+++ b/plugins/analysis/client/plugin.go
@@ -8,6 +8,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/autopeering/selection"
 	"github.com/iotaledger/goshimmer/packages/network"
 	"github.com/iotaledger/goshimmer/packages/parameter"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/addnode"
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/connectnodes"
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/disconnectnodes"
@@ -50,7 +51,7 @@ func Run(plugin *node.Plugin) {
 				}
 			}
 		}
-	})
+	}, shutdown.ShutdownPriorityAnalysis)
 }
 
 func getEventDispatchers(conn *network.ManagedConnection) *EventDispatchers {
diff --git a/plugins/analysis/server/plugin.go b/plugins/analysis/server/plugin.go
index 35973f84..a46f4c2f 100644
--- a/plugins/analysis/server/plugin.go
+++ b/plugins/analysis/server/plugin.go
@@ -7,6 +7,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/network"
 	"github.com/iotaledger/goshimmer/packages/network/tcp"
 	"github.com/iotaledger/goshimmer/packages/parameter"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/addnode"
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/connectnodes"
 	"github.com/iotaledger/goshimmer/plugins/analysis/types/disconnectnodes"
@@ -45,7 +46,7 @@ func Run(plugin *node.Plugin) {
 		go server.Listen(parameter.NodeConfig.GetInt(CFG_SERVER_PORT))
 		<-shutdownSignal
 		Shutdown()
-	})
+	}, shutdown.ShutdownPriorityAnalysis)
 }
 
 func Shutdown() {
diff --git a/plugins/analysis/webinterface/httpserver/plugin.go b/plugins/analysis/webinterface/httpserver/plugin.go
index 0299e173..fa3f2b50 100644
--- a/plugins/analysis/webinterface/httpserver/plugin.go
+++ b/plugins/analysis/webinterface/httpserver/plugin.go
@@ -4,6 +4,7 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/node"
 	"golang.org/x/net/context"
@@ -30,5 +31,5 @@ func Run(plugin *node.Plugin) {
 		ctx, cancel := context.WithTimeout(context.Background(), 0*time.Second)
 		defer cancel()
 		httpServer.Shutdown(ctx)
-	})
+	}, shutdown.ShutdownPriorityAnalysis)
 }
diff --git a/plugins/autopeering/plugin.go b/plugins/autopeering/plugin.go
index 04321f98..c6e9ec88 100644
--- a/plugins/autopeering/plugin.go
+++ b/plugins/autopeering/plugin.go
@@ -5,6 +5,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/autopeering/peer"
 	"github.com/iotaledger/goshimmer/packages/autopeering/selection"
 	"github.com/iotaledger/goshimmer/packages/gossip"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/logger"
@@ -23,7 +24,7 @@ func configure(*node.Plugin) {
 }
 
 func run(*node.Plugin) {
-	if err := daemon.BackgroundWorker(name, start); err != nil {
+	if err := daemon.BackgroundWorker(name, start, shutdown.ShutdownPriorityAutopeering); err != nil {
 		log.Errorf("Failed to start as daemon: %s", err)
 	}
 }
diff --git a/plugins/bundleprocessor/plugin.go b/plugins/bundleprocessor/plugin.go
index ad4ecb52..822a2952 100644
--- a/plugins/bundleprocessor/plugin.go
+++ b/plugins/bundleprocessor/plugin.go
@@ -3,6 +3,7 @@ package bundleprocessor
 import (
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
@@ -37,7 +38,7 @@ func run(*node.Plugin) {
 		log.Info("Stopping Bundle Processor ...")
 		workerPool.StopAndWait()
 		log.Info("Stopping Bundle Processor ... done")
-	})
+	}, shutdown.ShutdownPriorityBundleProcessor)
 
 	log.Info("Starting Value Bundle Processor ...")
 
@@ -48,5 +49,5 @@ func run(*node.Plugin) {
 		log.Info("Stopping Value Bundle Processor ...")
 		valueBundleProcessorWorkerPool.StopAndWait()
 		log.Info("Stopping Value Bundle Processor ... done")
-	})
+	}, shutdown.ShutdownPriorityBundleProcessor)
 }
diff --git a/plugins/dashboard/plugin.go b/plugins/dashboard/plugin.go
index 4321e0b5..5fa26f69 100644
--- a/plugins/dashboard/plugin.go
+++ b/plugins/dashboard/plugin.go
@@ -4,6 +4,7 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/metrics"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
@@ -48,5 +49,5 @@ func run(plugin *node.Plugin) {
 		ctx, cancel := context.WithTimeout(context.Background(), 0*time.Second)
 		defer cancel()
 		_ = server.Shutdown(ctx)
-	})
+	}, shutdown.ShutdownPriorityDashboard)
 }
diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go
index 0a4f61e4..3829565b 100644
--- a/plugins/gossip/plugin.go
+++ b/plugins/gossip/plugin.go
@@ -5,6 +5,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/autopeering/selection"
 	"github.com/iotaledger/goshimmer/packages/gossip"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
@@ -24,7 +25,7 @@ func configure(*node.Plugin) {
 }
 
 func run(*node.Plugin) {
-	if err := daemon.BackgroundWorker(name, start); err != nil {
+	if err := daemon.BackgroundWorker(name, start, shutdown.ShutdownPriorityGossip); err != nil {
 		log.Errorf("Failed to start as daemon: %s", err)
 	}
 }
diff --git a/plugins/graph/plugin.go b/plugins/graph/plugin.go
index 39e3df47..f6dcc3ee 100644
--- a/plugins/graph/plugin.go
+++ b/plugins/graph/plugin.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/parameter"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
 	"golang.org/x/net/context"
 
@@ -105,7 +106,7 @@ func run(plugin *node.Plugin) {
 		tangle.Events.TransactionStored.Detach(notifyNewTx)
 		newTxWorkerPool.Stop()
 		log.Info("Stopping Graph[NewTxWorker] ... done")
-	})
+	}, shutdown.ShutdownPriorityGraph)
 
 	daemon.BackgroundWorker("Graph Webserver", func(shutdownSignal <-chan struct{}) {
 		go socketioServer.Serve()
@@ -128,5 +129,5 @@ func run(plugin *node.Plugin) {
 
 		_ = server.Shutdown(ctx)
 		log.Info("Stopping Graph ... done")
-	})
+	}, shutdown.ShutdownPriorityGraph)
 }
diff --git a/plugins/metrics/plugin.go b/plugins/metrics/plugin.go
index 4774c72d..3624874e 100644
--- a/plugins/metrics/plugin.go
+++ b/plugins/metrics/plugin.go
@@ -4,6 +4,7 @@ import (
 	"time"
 
 	"github.com/iotaledger/goshimmer/packages/gossip"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/node"
@@ -21,5 +22,5 @@ func run(plugin *node.Plugin) {
 	// create a background worker that "measures" the TPS value every second
 	daemon.BackgroundWorker("Metrics TPS Updater", func(shutdownSignal <-chan struct{}) {
 		timeutil.Ticker(measureReceivedTPS, 1*time.Second, shutdownSignal)
-	})
+	}, shutdown.ShutdownPriorityMetrics)
 }
diff --git a/plugins/statusscreen-tps/plugin.go b/plugins/statusscreen-tps/plugin.go
index c4909e45..dbe6b892 100644
--- a/plugins/statusscreen-tps/plugin.go
+++ b/plugins/statusscreen-tps/plugin.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/iotaledger/goshimmer/packages/gossip"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/statusscreen"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
 	"github.com/iotaledger/hive.go/daemon"
@@ -51,5 +52,5 @@ var PLUGIN = node.NewPlugin("Statusscreen TPS", node.Enabled, func(plugin *node.
 				atomic.StoreUint64(&solidTpsCounter, 0)
 			}
 		}
-	})
+	}, shutdown.ShutdownPriorityStatusScreen)
 })
diff --git a/plugins/statusscreen/plugin.go b/plugins/statusscreen/plugin.go
index f79ca05e..e117234f 100644
--- a/plugins/statusscreen/plugin.go
+++ b/plugins/statusscreen/plugin.go
@@ -3,6 +3,7 @@ package statusscreen
 import (
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/logger"
@@ -57,7 +58,7 @@ func run(*node.Plugin) {
 				return
 			}
 		}
-	}); err != nil {
+	}, shutdown.ShutdownPriorityStatusScreen); err != nil {
 		log.Errorf("Failed to start as daemon: %s", err)
 		return
 	}
@@ -72,7 +73,7 @@ func run(*node.Plugin) {
 		if err := app.SetRoot(frame, true).SetFocus(frame).Run(); err != nil {
 			log.Errorf("Error running application: %s", err)
 		}
-	}); err != nil {
+	}, shutdown.ShutdownPriorityStatusScreen); err != nil {
 		log.Errorf("Failed to start as daemon: %s", err)
 		close(stopped)
 	}
diff --git a/plugins/tangle/approvers.go b/plugins/tangle/approvers.go
index 38d44aa9..166b1a7e 100644
--- a/plugins/tangle/approvers.go
+++ b/plugins/tangle/approvers.go
@@ -2,9 +2,9 @@ package tangle
 
 import (
 	"github.com/iotaledger/goshimmer/packages/database"
-	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/model/approvers"
+	"github.com/iotaledger/hive.go/lru_cache"
 	"github.com/iotaledger/hive.go/typeutils"
 	"github.com/iotaledger/iota.go/trinary"
 )
@@ -50,20 +50,26 @@ func StoreApprovers(approvers *approvers.Approvers) {
 
 // region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-var approversCache = datastructure.NewLRUCache(APPROVERS_CACHE_SIZE, &datastructure.LRUCacheOptions{
-	EvictionCallback: onEvictApprovers,
+var approversCache = lru_cache.NewLRUCache(APPROVERS_CACHE_SIZE, &lru_cache.LRUCacheOptions{
+	EvictionCallback:  onEvictApprovers,
+	EvictionBatchSize: 100,
 })
 
-func onEvictApprovers(_ interface{}, value interface{}) {
-	if evictedApprovers := value.(*approvers.Approvers); evictedApprovers.GetModified() {
-		go func(evictedApprovers *approvers.Approvers) {
-			if err := storeApproversInDatabase(evictedApprovers); err != nil {
+func onEvictApprovers(_ interface{}, values interface{}) {
+	// TODO: replace with apply
+	for _, obj := range values.([]interface{}) {
+		if approvers := obj.(*approvers.Approvers); approvers.GetModified() {
+			if err := storeApproversInDatabase(approvers); err != nil {
 				panic(err)
 			}
-		}(evictedApprovers)
+		}
 	}
 }
 
+func FlushApproversCache() {
+	approversCache.DeleteAll()
+}
+
 const (
 	APPROVERS_CACHE_SIZE = 50000
 )
diff --git a/plugins/tangle/bundle.go b/plugins/tangle/bundle.go
index fa607ba1..ca7208a9 100644
--- a/plugins/tangle/bundle.go
+++ b/plugins/tangle/bundle.go
@@ -2,9 +2,9 @@ package tangle
 
 import (
 	"github.com/iotaledger/goshimmer/packages/database"
-	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/model/bundle"
+	"github.com/iotaledger/hive.go/lru_cache"
 	"github.com/iotaledger/hive.go/typeutils"
 	"github.com/iotaledger/iota.go/trinary"
 )
@@ -54,20 +54,26 @@ func StoreBundle(bundle *bundle.Bundle) {
 
 // region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-var bundleCache = datastructure.NewLRUCache(BUNDLE_CACHE_SIZE, &datastructure.LRUCacheOptions{
-	EvictionCallback: onEvictBundle,
+var bundleCache = lru_cache.NewLRUCache(BUNDLE_CACHE_SIZE, &lru_cache.LRUCacheOptions{
+	EvictionCallback:  onEvictBundles,
+	EvictionBatchSize: 100,
 })
 
-func onEvictBundle(_ interface{}, value interface{}) {
-	if evictedBundle := value.(*bundle.Bundle); evictedBundle.GetModified() {
-		go func(evictedBundle *bundle.Bundle) {
-			if err := storeBundleInDatabase(evictedBundle); err != nil {
+func onEvictBundles(_ interface{}, values interface{}) {
+	// TODO: replace with apply
+	for _, obj := range values.([]interface{}) {
+		if bndl := obj.(*bundle.Bundle); bndl.GetModified() {
+			if err := storeBundleInDatabase(bndl); err != nil {
 				panic(err)
 			}
-		}(evictedBundle)
+		}
 	}
 }
 
+func FlushBundleCache() {
+	bundleCache.DeleteAll()
+}
+
 const (
 	BUNDLE_CACHE_SIZE = 500
 )
diff --git a/plugins/tangle/plugin.go b/plugins/tangle/plugin.go
index 483d57b7..252c2b98 100644
--- a/plugins/tangle/plugin.go
+++ b/plugins/tangle/plugin.go
@@ -1,6 +1,9 @@
 package tangle
 
 import (
+	"github.com/iotaledger/goshimmer/packages/database"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
+	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/iotaledger/hive.go/node"
 	"github.com/iotaledger/iota.go/trinary"
@@ -20,6 +23,22 @@ func configure(*node.Plugin) {
 	configureBundleDatabase()
 	configureTransactionHashesForAddressDatabase()
 	configureSolidifier()
+
+	daemon.BackgroundWorker("Cache Flush", func(shutdownSignal <-chan struct{}) {
+		<-shutdownSignal
+
+		log.Info("Flushing caches to database...")
+		FlushTransactionCache()
+		FlushTransactionMetadata()
+		FlushApproversCache()
+		FlushBundleCache()
+		log.Info("Flushing caches to database... done")
+
+		log.Info("Syncing database to disk...")
+		database.GetBadgerInstance().Close()
+		log.Info("Syncing database to disk... done")
+	}, shutdown.ShutdownPriorityTangle)
+
 }
 
 func run(*node.Plugin) {
diff --git a/plugins/tangle/solidifier.go b/plugins/tangle/solidifier.go
index 7e6e8c4f..2ab00159 100644
--- a/plugins/tangle/solidifier.go
+++ b/plugins/tangle/solidifier.go
@@ -10,6 +10,7 @@ import (
 	"github.com/iotaledger/goshimmer/packages/model/meta_transaction"
 	"github.com/iotaledger/goshimmer/packages/model/transactionmetadata"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/packages/workerpool"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
@@ -62,7 +63,7 @@ func runSolidifier() {
 		log.Info("Stopping Solidifier ...")
 		workerPool.StopAndWait()
 		log.Info("Stopping Solidifier ... done")
-	})
+	}, shutdown.ShutdownPrioritySolidifier)
 }
 
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/tangle/transaction.go b/plugins/tangle/transaction.go
index 31edfc4f..0de47154 100644
--- a/plugins/tangle/transaction.go
+++ b/plugins/tangle/transaction.go
@@ -2,9 +2,9 @@ package tangle
 
 import (
 	"github.com/iotaledger/goshimmer/packages/database"
-	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/hive.go/lru_cache"
 	"github.com/iotaledger/hive.go/typeutils"
 	"github.com/iotaledger/iota.go/trinary"
 )
@@ -51,20 +51,26 @@ func StoreTransaction(transaction *value_transaction.ValueTransaction) {
 
 // region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-var transactionCache = datastructure.NewLRUCache(TRANSACTION_CACHE_SIZE, &datastructure.LRUCacheOptions{
-	EvictionCallback: onEvictTransaction,
+var transactionCache = lru_cache.NewLRUCache(TRANSACTION_CACHE_SIZE, &lru_cache.LRUCacheOptions{
+	EvictionCallback:  onEvictTransactions,
+	EvictionBatchSize: 200,
 })
 
-func onEvictTransaction(_ interface{}, value interface{}) {
-	if evictedTransaction := value.(*value_transaction.ValueTransaction); evictedTransaction.GetModified() {
-		go func(evictedTransaction *value_transaction.ValueTransaction) {
-			if err := storeTransactionInDatabase(evictedTransaction); err != nil {
+func onEvictTransactions(_ interface{}, values interface{}) {
+	// TODO: replace with apply
+	for _, obj := range values.([]interface{}) {
+		if tx := obj.(*value_transaction.ValueTransaction); tx.GetModified() {
+			if err := storeTransactionInDatabase(tx); err != nil {
 				panic(err)
 			}
-		}(evictedTransaction)
+		}
 	}
 }
 
+func FlushTransactionCache() {
+	transactionCache.DeleteAll()
+}
+
 const (
 	TRANSACTION_CACHE_SIZE = 500
 )
diff --git a/plugins/tangle/transaction_metadata.go b/plugins/tangle/transaction_metadata.go
index 6713ecc8..0ea3c982 100644
--- a/plugins/tangle/transaction_metadata.go
+++ b/plugins/tangle/transaction_metadata.go
@@ -2,9 +2,9 @@ package tangle
 
 import (
 	"github.com/iotaledger/goshimmer/packages/database"
-	"github.com/iotaledger/goshimmer/packages/datastructure"
 	"github.com/iotaledger/goshimmer/packages/errors"
 	"github.com/iotaledger/goshimmer/packages/model/transactionmetadata"
+	"github.com/iotaledger/hive.go/lru_cache"
 	"github.com/iotaledger/hive.go/typeutils"
 	"github.com/iotaledger/iota.go/trinary"
 )
@@ -51,20 +51,26 @@ func StoreTransactionMetadata(transactionMetadata *transactionmetadata.Transacti
 
 // region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-var transactionMetadataCache = datastructure.NewLRUCache(TRANSACTION_METADATA_CACHE_SIZE, &datastructure.LRUCacheOptions{
-	EvictionCallback: onEvictTransactionMetadata,
+var transactionMetadataCache = lru_cache.NewLRUCache(TRANSACTION_METADATA_CACHE_SIZE, &lru_cache.LRUCacheOptions{
+	EvictionCallback:  onEvictTransactionMetadatas,
+	EvictionBatchSize: 200,
 })
 
-func onEvictTransactionMetadata(_ interface{}, value interface{}) {
-	if evictedTransactionMetadata := value.(*transactionmetadata.TransactionMetadata); evictedTransactionMetadata.GetModified() {
-		go func(evictedTransactionMetadata *transactionmetadata.TransactionMetadata) {
-			if err := storeTransactionMetadataInDatabase(evictedTransactionMetadata); err != nil {
+func onEvictTransactionMetadatas(_ interface{}, values interface{}) {
+	// TODO: replace with apply
+	for _, obj := range values.([]interface{}) {
+		if txMetadata := obj.(*transactionmetadata.TransactionMetadata); txMetadata.GetModified() {
+			if err := storeTransactionMetadataInDatabase(txMetadata); err != nil {
 				panic(err)
 			}
-		}(evictedTransactionMetadata)
+		}
 	}
 }
 
+func FlushTransactionMetadata() {
+	transactionCache.DeleteAll()
+}
+
 const (
 	TRANSACTION_METADATA_CACHE_SIZE = 500
 )
diff --git a/plugins/ui/ui.go b/plugins/ui/ui.go
index 9d9b8b1c..3c411210 100644
--- a/plugins/ui/ui.go
+++ b/plugins/ui/ui.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/iotaledger/goshimmer/packages/gossip"
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
 	"github.com/iotaledger/goshimmer/plugins/webapi"
 	"github.com/iotaledger/hive.go/daemon"
@@ -86,7 +87,7 @@ func run(plugin *node.Plugin) {
 				wsMutex.Unlock()
 			}
 		}
-	})
+	}, shutdown.ShutdownPriorityUI)
 }
 
 // PLUGIN plugs the UI into the main program
diff --git a/plugins/webapi/plugin.go b/plugins/webapi/plugin.go
index 6cd2e037..c7bd41f3 100644
--- a/plugins/webapi/plugin.go
+++ b/plugins/webapi/plugin.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/logger"
 	"github.com/iotaledger/hive.go/node"
@@ -43,5 +44,5 @@ func run(plugin *node.Plugin) {
 		if err := Server.Shutdown(ctx); err != nil {
 			log.Errorf("Couldn't stop server cleanly: %s", err.Error())
 		}
-	})
+	}, shutdown.ShutdownPriorityWebAPI)
 }
diff --git a/plugins/webauth/webauth.go b/plugins/webauth/webauth.go
index 2b904878..aa7ba5b3 100644
--- a/plugins/webauth/webauth.go
+++ b/plugins/webauth/webauth.go
@@ -6,6 +6,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/webapi"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/node"
@@ -66,7 +67,7 @@ func run(plugin *node.Plugin) {
 				"token": t,
 			})
 		})
-	})
+	}, shutdown.ShutdownPriorityWebAPI)
 }
 
 // PLUGIN plugs the UI into the main program
diff --git a/plugins/zeromq/plugin.go b/plugins/zeromq/plugin.go
index 11ddb33c..0bf553b3 100644
--- a/plugins/zeromq/plugin.go
+++ b/plugins/zeromq/plugin.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
 	"github.com/iotaledger/goshimmer/packages/parameter"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
 	"github.com/iotaledger/hive.go/daemon"
 	"github.com/iotaledger/hive.go/events"
@@ -53,7 +54,7 @@ func run(plugin *node.Plugin) {
 		} else {
 			log.Info("Stopping ZeroMQ Publisher ... done")
 		}
-	})
+	}, shutdown.ShutdownPriorityZMQ)
 }
 
 // Start the zmq publisher.
-- 
GitLab