about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAlan Pearce2025-03-19 20:49:46 +0100
committerAlan Pearce2025-03-19 20:51:40 +0100
commit383ee780613116e78db9114a39a2d6127533463c (patch)
treec07e2af7ae910d5c6f80836dce8457ba44c54ceb
parent49e3004d33bf84aa081460e4a6d89a8d84cc12b0 (diff)
downloadsearchix-383ee780613116e78db9114a39a2d6127533463c.tar.lz
searchix-383ee780613116e78db9114a39a2d6127533463c.tar.zst
searchix-383ee780613116e78db9114a39a2d6127533463c.zip
feat: show last/next/current indexing run time
-rw-r--r--internal/components/data.go28
-rw-r--r--internal/components/search.go36
-rw-r--r--internal/index/index_meta.go11
-rw-r--r--internal/index/search.go5
-rw-r--r--searchix.go5
5 files changed, 85 insertions, 0 deletions
diff --git a/internal/components/data.go b/internal/components/data.go
index 977b90e..9bc0c5e 100644
--- a/internal/components/data.go
+++ b/internal/components/data.go
@@ -1,12 +1,21 @@
 package components
 
 import (
+	"time"
+
 	"go.alanpearce.eu/searchix/frontend"
 	"go.alanpearce.eu/searchix/internal/config"
 	search "go.alanpearce.eu/searchix/internal/index"
 	"go.alanpearce.eu/searchix/internal/nix"
 )
 
+var Indexing struct {
+	InProgress bool
+	StartedAt  time.Time
+	FinishedAt time.Time
+	NextRun    time.Time
+}
+
 type TemplateData struct {
 	Sources       []*config.Source
 	Source        *config.Source
@@ -34,3 +43,22 @@ func convertMatch[I nix.Importable](m nix.Importable) *I {
 
 	return &i
 }
+
+func SetNextRun(nextRun time.Time) {
+	Indexing.NextRun = nextRun
+}
+
+func SetLastUpdated(last time.Time) {
+	Indexing.FinishedAt = last
+}
+
+func MarkIndexingStarted() {
+	Indexing.StartedAt = time.Now()
+	Indexing.InProgress = true
+}
+
+func MarkIndexingFinished(nextRun time.Time) {
+	Indexing.FinishedAt = time.Now()
+	Indexing.InProgress = false
+	Indexing.NextRun = nextRun
+}
diff --git a/internal/components/search.go b/internal/components/search.go
index 0a7c991..d629eef 100644
--- a/internal/components/search.go
+++ b/internal/components/search.go
@@ -1,6 +1,8 @@
 package components
 
 import (
+	"time"
+
 	g "go.alanpearce.eu/gomponents"
 	. "go.alanpearce.eu/gomponents/html"
 )
@@ -40,6 +42,40 @@ func SearchPage(tdata TemplateData, r ResultData, children ...g.Node) g.Node {
 			g.Text(" and "),
 			A(Href("https://github.com/nix-community/home-manager"), g.Text("home-manager")),
 		),
+		g.If(Indexing.InProgress,
+			P(Class("notice"),
+				g.Text("Indexing in progress, started "),
+				Time(
+					DateTime(Indexing.StartedAt.Format(time.RFC3339)),
+					Title(Indexing.StartedAt.Format(time.RFC3339)),
+					g.Text(time.Since(Indexing.StartedAt).Round(time.Second).String()),
+				),
+				g.Text(" ago. "),
+				g.If(!Indexing.FinishedAt.IsZero(),
+					g.Text("Last run took "),
+					Time(
+						DateTime(Indexing.FinishedAt.Format(time.RFC3339)),
+						Title(Indexing.FinishedAt.Format(time.RFC3339)),
+						g.Text(time.Since(Indexing.FinishedAt).Round(time.Minute).String()),
+					),
+				),
+			),
+			P(
+				g.Text("Indexing last ran "),
+				Time(
+					DateTime(Indexing.FinishedAt.Format(time.RFC3339)),
+					Title(Indexing.FinishedAt.Format(time.RFC3339)),
+					g.Text(time.Since(Indexing.FinishedAt).Round(time.Minute).String()),
+				),
+				g.Text(" ago, will run again in "),
+				Time(
+					DateTime(Indexing.NextRun.Format(time.RFC3339)),
+					Title(Indexing.NextRun.Format(time.RFC3339)),
+					g.Text(time.Until(Indexing.NextRun).Round(time.Minute).String()),
+				),
+				g.Text("."),
+			),
+		),
 		script(tdata.Assets.ByPath["/static/search.js"]),
 		Search(tdata, r),
 		Section(
diff --git a/internal/index/index_meta.go b/internal/index/index_meta.go
index 635965a..0ff835b 100644
--- a/internal/index/index_meta.go
+++ b/internal/index/index_meta.go
@@ -118,3 +118,14 @@ func (i *Meta) SetSourceMeta(source string, meta *SourceMeta) {
 	}
 	i.data.Sources[source] = meta
 }
+
+func (i *Meta) LastUpdated() time.Time {
+	var last time.Time
+	for _, sourceMeta := range i.data.Sources {
+		if sourceMeta.Updated.After(last) {
+			last = sourceMeta.Updated
+		}
+	}
+
+	return last
+}
diff --git a/internal/index/search.go b/internal/index/search.go
index 3f9c13a..d5bf177 100644
--- a/internal/index/search.go
+++ b/internal/index/search.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"context"
 	"encoding/gob"
+	"time"
 
 	"go.alanpearce.eu/searchix/internal/config"
 	"go.alanpearce.eu/searchix/internal/nix"
@@ -33,6 +34,10 @@ type ReadIndex struct {
 	meta  *Meta
 }
 
+func (index *ReadIndex) LastUpdated() time.Time {
+	return index.meta.LastUpdated()
+}
+
 func (index *ReadIndex) GetEnabledSources() ([]string, errors.E) {
 	facet := bleve.NewFacetRequest("Source", 100)
 	query := bleve.NewMatchAllQuery()
diff --git a/searchix.go b/searchix.go
index 1c870df..8bd696d 100644
--- a/searchix.go
+++ b/searchix.go
@@ -7,6 +7,7 @@ import (
 	"sync"
 	"time"
 
+	"go.alanpearce.eu/searchix/internal/components"
 	"go.alanpearce.eu/searchix/internal/config"
 	"go.alanpearce.eu/searchix/internal/importer"
 	"go.alanpearce.eu/searchix/internal/index"
@@ -125,6 +126,7 @@ func (s *Server) SetupIndex(ctx context.Context, options *IndexOptions) errors.E
 			}
 		}
 	}
+	components.SetLastUpdated(read.LastUpdated())
 
 	return nil
 }
@@ -175,6 +177,7 @@ func (s *Server) startUpdateTimer(
 
 		s.wg.Add(1)
 		nextRun := nextUTCOccurrenceOfTime(s.cfg.Importer.UpdateAt)
+		components.SetNextRun(nextRun)
 		for {
 			s.log.Debug("scheduling next run", "next-run", nextRun)
 			select {
@@ -192,6 +195,7 @@ func (s *Server) startUpdateTimer(
 				MonitorSlug: monitorSlug,
 				Status:      sentry.CheckInStatusInProgress,
 			}, monitorConfig)
+			components.MarkIndexingStarted()
 
 			imp := importer.New(s.cfg, s.log.Named("importer"), s.writeIndex)
 			err = imp.Start(ctx, false, nil)
@@ -215,6 +219,7 @@ func (s *Server) startUpdateTimer(
 				}, monitorConfig)
 			}
 			nextRun = nextRun.AddDate(0, 0, 1)
+			components.MarkIndexingFinished(nextRun)
 		}
 	})
 }