Rework some things to prepare for the cleanup of old diagrams

This commit is contained in:
Tom Wright 2020-08-08 00:21:39 +01:00
parent c4c6859846
commit 0461b59150
7 changed files with 115 additions and 64 deletions

View File

@ -1,61 +1,14 @@
package main
import (
"context"
"flag"
"fmt"
"github.com/tomwright/lifetime"
"github.com/tomwright/mermaid-server/internal"
"log"
"net/http"
"os"
)
var testInput = []byte(`
graph TB
subgraph "Jira"
createTicket["Create ticket"]
updateTicket["Update ticket"]
fireWebhook["Fire webhook"]
createTicket-->fireWebhook
updateTicket-->fireWebhook
end
subgraph "Jira Webhook"
receiveWebhook["Receive webhook"]
storeEvent["Store event in immutable list"]
publishNewStoredEventEvent["Publish message to notify system of new event"]
createEvent["Create internal event that will be stored"]
setCreatedAt["Set created at date to now"]
setSourceJira["Set source to Jira webhook"]
receiveWebhook-->createEvent-->setCreatedAt-->setSourceJira-->storeEvent
storeEvent-->publishNewStoredEventEvent
end
fireWebhook-->receiveWebhook
subgraph "Play Event"
publishEventUpdated["Publish message to notify system of new status"]
verifyEventSource["Verify event source"]
parsePayload["Parse event payload using source to determine structure"]
findEventHandler["Find the handler for the specific event type + version"]
getLatestPersistedState["Get latest persisted state"]
changeInMemoryStateUsingEventData["Change in-memory state using event data"]
persistUpdatedState["Persist updated state"]
verifyEventSource-->parsePayload
parsePayload-->findEventHandler
findEventHandler-->getLatestPersistedState-->changeInMemoryStateUsingEventData-->persistUpdatedState
persistUpdatedState-->publishEventUpdated
end
publishNewStoredEventEvent-->verifyEventSource
`)
func main() {
mermaid := flag.String("mermaid", "", "The full path to the mermaidcli executable.")
in := flag.String("in", "", "Directory to store input files.")
@ -81,20 +34,16 @@ func main() {
cache := internal.NewDiagramCache()
generator := internal.NewGenerator(cache, *mermaid, *in, *out, *puppeteer)
httpHandler := internal.GenerateHTTPHandler(generator)
httpService := internal.NewHTTPService(generator)
cleanupService := internal.NewCleanupService(generator)
r := http.NewServeMux()
r.Handle("/generate", http.HandlerFunc(httpHandler))
lt := lifetime.New(context.Background()).Init()
httpServer := &http.Server{
Addr: ":80",
Handler: r,
}
log.Printf("Listening on address %s", httpServer.Addr)
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("Could not listen for http connections: %s", err)
os.Exit(1)
}
// Start the http service.
lt.Start(httpService)
// Start the cleanup service.
lt.Start(cleanupService)
log.Printf("Shutdown")
// Wait for all routines to stop running.
lt.Wait()
}

2
go.mod
View File

@ -1,3 +1,5 @@
module github.com/tomwright/mermaid-server
go 1.13
require github.com/tomwright/lifetime v1.0.0

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/tomwright/lifetime v1.0.0 h1:Yzj+Td38eUUdZ1ewvOegywFBmKyaCh+8HjKBmeXw6OM=
github.com/tomwright/lifetime v1.0.0/go.mod h1:GUCHgRaR/zStvtJiOd3B4gIZayeiz3TgApC9kNYAOQI=

View File

@ -0,0 +1,41 @@
package internal
import (
"log"
"time"
)
// NewCleanupService returns a service that can be used cleanup old diagrams.
func NewCleanupService(generator Generator) *cleanupService {
return &cleanupService{
generator: generator,
stopCh: make(chan struct{}),
}
}
// cleanupService is a service that can be used cleanup old diagrams.
type cleanupService struct {
generator Generator
stopCh chan struct{}
}
// Start starts the cleanup service.
func (s *cleanupService) Start() error {
for {
if err := s.generator.CleanUp(time.Hour); err != nil {
log.Printf("error when cleaning up: %s", err.Error())
}
select {
case <-time.After(time.Minute * 5):
continue
case <-s.stopCh:
return nil
}
}
}
// Stop stops the cleanup service.
func (s *cleanupService) Stop() {
close(s.stopCh)
}

View File

@ -8,14 +8,18 @@ import (
"log"
"os"
"os/exec"
"time"
)
// Generator provides the ability to generate a diagram.
type Generator interface {
// Generate generates the given diagram.
Generate(diagram *Diagram) error
// CleanUp removes any diagrams that haven't used within the given duration.
CleanUp(duration time.Duration) error
}
// NewGenerator returns a generator that can be used to generate diagrams.
func NewGenerator(cache DiagramCache, mermaidCLIPath string, inPath string, outPath string, puppeteerConfigPath string) Generator {
return &cachingGenerator{
cache: cache,
@ -102,3 +106,9 @@ func (c cachingGenerator) generate(diagram *Diagram) error {
return nil
}
// CleanUp removes any diagrams that haven't used within the given duration.
func (c cachingGenerator) CleanUp(duration time.Duration) error {
// todo : loop through all cached diagrams and delete any that haven't been used within duration.
return nil
}

View File

@ -80,8 +80,8 @@ func getDiagramFromPOST(rw http.ResponseWriter, r *http.Request) *Diagram {
return d
}
// GenerateHTTPHandler returns a HTTP handler used to generate a diagram.
func GenerateHTTPHandler(generator Generator) func(rw http.ResponseWriter, r *http.Request) {
// generateHTTPHandler returns a HTTP handler used to generate a diagram.
func generateHTTPHandler(generator Generator) func(rw http.ResponseWriter, r *http.Request) {
return func(rw http.ResponseWriter, r *http.Request) {
var diagram *Diagram

47
internal/http_service.go Normal file
View File

@ -0,0 +1,47 @@
package internal
import (
"net/http"
)
// NewHTTPService returns a service that can be used to start a http server
// that will generate diagrams.
func NewHTTPService(generator Generator) *httpService {
return &httpService{
generator: generator,
}
}
// httpService is a service that can be used to start a http server
// that will generate diagrams.
type httpService struct {
httpServer *http.Server
generator Generator
}
// Start starts the HTTP server.
func (s *httpService) Start() error {
httpHandler := generateHTTPHandler(s.generator)
r := http.NewServeMux()
r.Handle("/generate", http.HandlerFunc(httpHandler))
s.httpServer = &http.Server{
Addr: ":80",
Handler: r,
}
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
if err != http.ErrServerClosed {
return err
}
}
return nil
}
func (s *httpService) Stop() {
if s != nil {
_ = s.httpServer.Close()
}
}