From 9998582575aa02dbd2206497953f207af1f117d2 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Thu, 31 Jul 2025 00:31:28 +0700 Subject: all: implement Start and Stop methods on the Service The Start method start the scanning periodically and send the report to channel reportq. The Stop method stop the periodic scanning. This changes introduces new option Interval in the Service that define the time interval between each scan. --- scan_report.go | 2 ++ service.go | 25 +++++++++++++++++++++++++ service_options.go | 25 ++++++++++++++++++++++++- service_test.go | 10 +++++++--- worker_test.go | 19 +++++++++++-------- 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/scan_report.go b/scan_report.go index 16034de..6544dc7 100644 --- a/scan_report.go +++ b/scan_report.go @@ -7,6 +7,8 @@ import "time" // ScanReport contains the result of scanning service. type ScanReport struct { + Name string + // The time when the scan started. At time.Time diff --git a/service.go b/service.go index 974c648..b1bf11c 100644 --- a/service.go +++ b/service.go @@ -8,6 +8,7 @@ import ( "log" "net" "net/http" + "time" "git.sr.ht/~shulhan/lilin/internal" ) @@ -15,6 +16,7 @@ import ( type Service struct { httpConn *http.Client dialer *net.Dialer + ticker *time.Ticker opts ServiceOptions isReady bool } @@ -35,6 +37,7 @@ func NewService(opts ServiceOptions) (svc *Service, err error) { func (svc *Service) Scan() (report ScanReport) { var err error + report.Name = svc.opts.Name report.At = internal.Now() if !svc.isReady { err = svc.connect() @@ -77,6 +80,28 @@ func (svc *Service) Scan() (report ScanReport) { return report } +// Start scanning periodically and send the report to reportq. +func (svc *Service) Start(reportq chan<- ScanReport) { + svc.ticker = time.NewTicker(svc.opts.interval) + + reportq <- svc.Scan() + + for { + _, ok := <-svc.ticker.C + if !ok { + log.Printf("Service: %s not ok", svc.opts.Name) + return + } + log.Printf(`Scan %s started`, svc.opts.Name) + reportq <- svc.Scan() + } +} + +// Stop the periodic scanning. +func (svc *Service) Stop() { + svc.ticker.Stop() +} + func (svc *Service) connect() (err error) { switch svc.opts.scanURL.Scheme { case serviceKindHTTP, serviceKindHTTPS: diff --git a/service_options.go b/service_options.go index 957987a..fc0da11 100644 --- a/service_options.go +++ b/service_options.go @@ -5,6 +5,7 @@ package lilin import ( "fmt" + "log" "net" "net/http" "net/url" @@ -19,6 +20,9 @@ const ( serviceKindUDP = `udp` ) +// defInterval define default interval in between scanning run. +const defInterval = 1 * time.Minute + type ServiceOptions struct { scanURL *url.URL @@ -37,7 +41,12 @@ type ServiceOptions struct { // Timeout for connecting and reading response from service. Timeout string `ini:"::timeout"` - timeout time.Duration + // Interval between each scan. + // The minimum value is 60 seconds or 1 minute. + Interval string `ini:"::interval"` + + timeout time.Duration + interval time.Duration } func (opts *ServiceOptions) init() (err error) { @@ -85,5 +94,19 @@ func (opts *ServiceOptions) init() (err error) { return fmt.Errorf(`invalid Timeout %s`, opts.Timeout) } } + + if len(opts.Interval) == 0 { + opts.interval = defInterval + } else { + opts.interval, err = time.ParseDuration(opts.Interval) + if err != nil { + return fmt.Errorf(`invalid Interval %s`, opts.Interval) + } + if opts.interval < defInterval { + log.Printf(`%s: interval is less than %s, revert to default`, + opts.Name, defInterval) + opts.interval = defInterval + } + } return nil } diff --git a/service_test.go b/service_test.go index 02285cb..bd58b91 100644 --- a/service_test.go +++ b/service_test.go @@ -11,10 +11,10 @@ import ( "git.sr.ht/~shulhan/pakakeh.go/lib/test" ) -func TestServiceScan_HTTP(t *testing.T) { +func TestServiceStart_HTTP(t *testing.T) { type testCase struct { - opts lilin.ServiceOptions expReport lilin.ScanReport + opts lilin.ServiceOptions } var listCase = []testCase{{ @@ -23,18 +23,22 @@ func TestServiceScan_HTTP(t *testing.T) { Address: `http://` + dummyHTTPAddress + `/health`, }, expReport: lilin.ScanReport{ + Name: `http_service`, At: internal.Now(), Success: true, }, }} + var reportq = make(chan lilin.ScanReport, 1) for _, tcase := range listCase { svc, err := lilin.NewService(tcase.opts) if err != nil { t.Fatal(err) } - var gotReport = svc.Scan() + go svc.Start(reportq) + var gotReport = <-reportq + svc.Stop() test.Assert(t, `Scan`, tcase.expReport, gotReport) } diff --git a/worker_test.go b/worker_test.go index 83fcc69..46e7cd3 100644 --- a/worker_test.go +++ b/worker_test.go @@ -39,6 +39,7 @@ func TestNewWorker(t *testing.T) { Address: `http://127.0.0.1:6121/health`, Timeout: `5s`, timeout: 5 * time.Second, + interval: defInterval, }, }, `example tcp`: &Service{ @@ -47,10 +48,11 @@ func TestNewWorker(t *testing.T) { Scheme: `tcp`, Host: `127.0.0.1:6122`, }, - Name: `example tcp`, - Address: `tcp://127.0.0.1:6122`, - Timeout: `5s`, - timeout: 5 * time.Second, + Name: `example tcp`, + Address: `tcp://127.0.0.1:6122`, + Timeout: `5s`, + timeout: 5 * time.Second, + interval: defInterval, }, }, `example udp`: &Service{ @@ -59,10 +61,11 @@ func TestNewWorker(t *testing.T) { Scheme: `udp`, Host: `127.0.0.1:6123`, }, - Name: `example udp`, - Address: `udp://127.0.0.1:6123`, - Timeout: `5s`, - timeout: 5 * time.Second, + Name: `example udp`, + Address: `udp://127.0.0.1:6123`, + Timeout: `5s`, + timeout: 5 * time.Second, + interval: defInterval, }, }, }, -- cgit v1.3