Skip to content

Commit

Permalink
checkins - comments
Browse files Browse the repository at this point in the history
  • Loading branch information
hunterlong committed Oct 7, 2018
1 parent 9acdd46 commit 8a08a9d
Show file tree
Hide file tree
Showing 18 changed files with 232 additions and 80 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION=0.73
VERSION=0.74
BINARY_NAME=statup
GOPATH:=$(GOPATH)
GOCMD=go
Expand Down Expand Up @@ -37,7 +37,7 @@ build-all: build-mac build-linux build-windows build-alpine compress
docker-build-all: docker-build-base docker-build-dev docker-build-latest

# push all docker tags built
docker-publish-all: docker-push-base docker-push-dev
docker-publish-all: docker-push-base docker-push-dev docker-push-latest

# build Statup for local arch
build: compile
Expand Down
118 changes: 91 additions & 27 deletions core/checkin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,84 +23,148 @@ import (
"time"
)

type checkin struct {
type Checkin struct {
*types.Checkin
}

type checkinHit struct {
*types.CheckinHit
}

// String will return a checkin API string
func (c *checkin) String() string {
// Routine for checking if the last Checkin was within its interval
func (c *Checkin) Routine() {
if c.Last() == nil {
return
}
reCheck := c.Period()
CheckinLoop:
for {
select {
case <-c.Running:
utils.Log(1, fmt.Sprintf("Stopping checkin routing: %v", c.Name))
break CheckinLoop
case <-time.After(reCheck):
utils.Log(1, fmt.Sprintf("checking %v is expected at %v, checking every %v", c.Name, c.Expected(), c.Period()))
if c.Expected().Seconds() <= 0 {
issue := fmt.Sprintf("checkin is failing, no request since %v", c.Last().CreatedAt)
utils.Log(3, issue)
c.Service()
c.CreateFailure()
}
reCheck = c.Period()
}
continue
}
}

// String will return a Checkin API string
func (c *Checkin) String() string {
return c.ApiKey
}

// ReturnCheckin converts *types.Checking to *core.checkin
func ReturnCheckin(c *types.Checkin) *checkin {
return &checkin{Checkin: c}
// ReturnCheckin converts *types.Checking to *core.Checkin
func ReturnCheckin(c *types.Checkin) *Checkin {
return &Checkin{Checkin: c}
}

// ReturnCheckinHit converts *types.checkinHit to *core.checkinHit
func ReturnCheckinHit(c *types.CheckinHit) *checkinHit {
return &checkinHit{CheckinHit: c}
}

// SelectCheckin will find a checkin based on the API supplied
func SelectCheckin(api string) *checkin {
var checkin checkin
func (c *Checkin) Service() *Service {
service := SelectService(c.ServiceId)
return service
}

func (c *Checkin) CreateFailure() (int64, error) {
service := c.Service()
fail := &types.Failure{
Issue: fmt.Sprintf("Checkin %v was not reported %v ago, it expects a request every %v", c.Name, utils.FormatDuration(c.Expected()), utils.FormatDuration(c.Period())),
Method: "checkin",
MethodId: c.Id,
Service: service.Id,
PingTime: c.Expected().Seconds() * 0.001,
}
row := failuresDB().Create(&fail)
return fail.Id, row.Error
}

// SelectCheckin will find a Checkin based on the API supplied
func SelectCheckin(api string) *Checkin {
var checkin Checkin
checkinDB().Where("api_key = ?", api).First(&checkin)
return &checkin
}

// Period will return the duration of the checkin interval
func (c *checkin) Period() time.Duration {
// SelectCheckin will find a Checkin based on the API supplied
func SelectCheckinId(id int64) *Checkin {
var checkin Checkin
checkinDB().Where("id = ?", id).First(&checkin)
return &checkin
}

// Period will return the duration of the Checkin interval
func (c *Checkin) Period() time.Duration {
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", c.Interval))
return duration
}

// Grace will return the duration of the checkin Grace Period (after service hasn't responded, wait a bit for a response)
func (c *checkin) Grace() time.Duration {
// Grace will return the duration of the Checkin Grace Period (after service hasn't responded, wait a bit for a response)
func (c *Checkin) Grace() time.Duration {
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", c.GracePeriod))
return duration
}

// Expected returns the duration of when the serviec should receive a checkin
func (c *checkin) Expected() time.Duration {
// Expected returns the duration of when the serviec should receive a Checkin
func (c *Checkin) Expected() time.Duration {
last := c.Last().CreatedAt
now := time.Now()
lastDir := now.Sub(last)
sub := time.Duration(c.Period() - lastDir)
return sub
}

// Last returns the last checkinHit for a checkin
func (c *checkin) Last() checkinHit {
// Last returns the last checkinHit for a Checkin
func (c *Checkin) Last() *checkinHit {
var hit checkinHit
checkinHitsDB().Where("checkin = ?", c.Id).Last(&hit)
return hit
return &hit
}

// Hits returns all of the CheckinHits for a given checkin
func (c *checkin) Hits() []checkinHit {
var checkins []checkinHit
func (c *Checkin) Link() string {
return fmt.Sprintf("%v/checkin/%v", CoreApp.Domain, c.ApiKey)
}

// Hits returns all of the CheckinHits for a given Checkin
func (c *Checkin) Hits() []*checkinHit {
var checkins []*checkinHit
checkinHitsDB().Where("checkin = ?", c.Id).Order("id DESC").Find(&checkins)
return checkins
}

// Create will create a new checkin
func (c *checkin) Create() (int64, error) {
// Create will create a new Checkin
func (c *Checkin) Delete() error {
c.Close()
row := checkinDB().Delete(&c)
return row.Error
}

// Create will create a new Checkin
func (c *Checkin) Create() (int64, error) {
c.ApiKey = utils.RandomString(7)
row := checkinDB().Create(&c)
c.Start()
go c.Routine()
if row.Error != nil {
utils.Log(2, row.Error)
return 0, row.Error
}
return c.Id, row.Error
}

// Update will update a checkin
func (c *checkin) Update() (int64, error) {
// Update will update a Checkin
func (c *Checkin) Update() (int64, error) {
row := checkinDB().Update(c)
if row.Error != nil {
utils.Log(2, row.Error)
Expand Down Expand Up @@ -128,8 +192,8 @@ func (c *checkinHit) Ago() string {
return got
}

// RecheckCheckinFailure will check if a Service checkin has been reported yet
func (c *checkin) RecheckCheckinFailure(guard chan struct{}) {
// RecheckCheckinFailure will check if a Service Checkin has been reported yet
func (c *Checkin) RecheckCheckinFailure(guard chan struct{}) {
between := time.Now().Sub(time.Now()).Seconds()
if between > float64(c.Interval) {
fmt.Println("rechecking every 15 seconds!")
Expand Down
12 changes: 6 additions & 6 deletions core/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ func usersDB() *gorm.DB {
return DbSession.Model(&types.User{})
}

// checkinDB returns the checkin records for a service
// checkinDB returns the Checkin records for a service
func checkinDB() *gorm.DB {
return DbSession.Model(&types.Checkin{})
}

// checkinHitsDB returns the 'hits' from the checkin record
// checkinHitsDB returns the 'hits' from the Checkin record
func checkinHitsDB() *gorm.DB {
return DbSession.Model(&types.CheckinHit{})
}
Expand Down Expand Up @@ -115,8 +115,8 @@ func (u *user) AfterFind() (err error) {
return
}

// AfterFind for checkin will set the timezone
func (c *checkin) AfterFind() (err error) {
// AfterFind for Checkin will set the timezone
func (c *Checkin) AfterFind() (err error) {
c.CreatedAt = utils.Timezoner(c.CreatedAt, CoreApp.Timezone)
return
}
Expand Down Expand Up @@ -159,8 +159,8 @@ func (s *Service) BeforeCreate() (err error) {
return
}

// BeforeCreate for checkin will set CreatedAt to UTC
func (c *checkin) BeforeCreate() (err error) {
// BeforeCreate for Checkin will set CreatedAt to UTC
func (c *Checkin) BeforeCreate() (err error) {
if c.CreatedAt.IsZero() {
c.CreatedAt = time.Now().UTC()
}
Expand Down
7 changes: 5 additions & 2 deletions core/failures.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (s *Service) CreateFailure(f *types.Failure) (int64, error) {
// AllFailures will return all failures attached to a service
func (s *Service) AllFailures() []*failure {
var fails []*failure
col := failuresDB().Where("service = ?", s.Id).Order("id desc")
col := failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc")
err := col.Find(&fails)
if err.Error != nil {
utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err))
Expand Down Expand Up @@ -123,13 +123,16 @@ func (s *Service) TotalFailures() (uint64, error) {
// TotalFailuresSince returns the total amount of failures for a service since a specific time/date
func (s *Service) TotalFailuresSince(ago time.Time) (uint64, error) {
var count uint64
rows := failuresDB().Where("service = ? AND created_at > ?", s.Id, ago.UTC().Format("2006-01-02 15:04:05"))
rows := failuresDB().Where("service = ? AND created_at > ?", s.Id, ago.UTC().Format("2006-01-02 15:04:05")).Not("method = 'checkin'")
err := rows.Count(&count)
return count, err.Error
}

// ParseError returns a human readable error for a failure
func (f *failure) ParseError() string {
if f.Method == "checkin" {
return fmt.Sprintf("Checkin is Offline")
}
err := strings.Contains(f.Issue, "connection reset by peer")
if err {
return fmt.Sprintf("Connection Reset")
Expand Down
2 changes: 1 addition & 1 deletion core/hits.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type Hit struct {

// CreateHit will create a new 'hit' record in the database for a successful/online service
func (s *Service) CreateHit(h *types.Hit) (int64, error) {
db := hitsDB().Create(h)
db := hitsDB().Create(&h)
if db.Error != nil {
utils.Log(2, db.Error)
return 0, db.Error
Expand Down
6 changes: 3 additions & 3 deletions core/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,19 @@ func InsertSampleData() error {
return nil
}

// insertSampleCheckins will create 2 checkins with 60 successful hits per checkin
// insertSampleCheckins will create 2 checkins with 60 successful hits per Checkin
func insertSampleCheckins() error {
s1 := SelectService(1)
checkin1 := ReturnCheckin(&types.Checkin{
Service: s1.Id,
ServiceId: s1.Id,
Interval: 300,
GracePeriod: 300,
})
checkin1.Update()

s2 := SelectService(1)
checkin2 := ReturnCheckin(&types.Checkin{
Service: s2.Id,
ServiceId: s2.Id,
Interval: 900,
GracePeriod: 300,
})
Expand Down
22 changes: 19 additions & 3 deletions core/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,29 @@ func SelectService(id int64) *Service {
return nil
}

// CheckinProcess runs the checkin routine for each checkin attached to service
func (s *Service) CheckinProcess() {
checkins := s.Checkins()
for _, c := range checkins {
c.Start()
go c.Routine()
}
}

// Checkins will return a slice of Checkins for a Service
func (s *Service) Checkins() []*checkin {
var checkin []*checkin
func (s *Service) Checkins() []*Checkin {
var checkin []*Checkin
checkinDB().Where("service = ?", s.Id).Find(&checkin)
return checkin
}

// LimitedCheckins will return a slice of Checkins for a Service
func (s *Service) LimitedCheckins() []*Checkin {
var checkin []*Checkin
checkinDB().Where("service = ?", s.Id).Limit(10).Find(&checkin)
return checkin
}

// SelectAllServices returns a slice of *core.Service to be store on []*core.Services, should only be called once on startup.
func (c *Core) SelectAllServices() ([]*Service, error) {
var services []*Service
Expand All @@ -69,7 +85,7 @@ func (c *Core) SelectAllServices() ([]*Service, error) {
CoreApp.Services = nil
for _, service := range services {
service.Start()
service.Checkins()
service.CheckinProcess()
service.AllFailures()
CoreApp.Services = append(CoreApp.Services, service)
}
Expand Down
2 changes: 1 addition & 1 deletion core/services_checkin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
)

var (
testCheckin *checkin
testCheckin *Checkin
)

func TestCreateCheckin(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap
"NewUser": func() *types.User {
return new(types.User)
},
"NewCheckin": func() *types.Checkin {
return new(types.Checkin)
},
}
}

Expand Down
5 changes: 3 additions & 2 deletions handlers/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ func Router() *mux.Router {
r.Handle("/service/{id}/edit", http.HandlerFunc(servicesViewHandler))
r.Handle("/service/{id}/delete", http.HandlerFunc(servicesDeleteHandler))
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(servicesDeleteFailuresHandler)).Methods("GET")
r.Handle("/service/{id}/checkin", http.HandlerFunc(checkinCreateUpdateHandler)).Methods("POST")
r.Handle("/checkin/{id}", http.HandlerFunc(checkinUpdateHandler))
r.Handle("/service/{id}/checkin", http.HandlerFunc(checkinCreateHandler)).Methods("POST")
r.Handle("/checkin/{id}/delete", http.HandlerFunc(checkinDeleteHandler)).Methods("GET")
r.Handle("/checkin/{id}", http.HandlerFunc(checkinHitHandler))

// API SERVICE Routes
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
Expand Down
Loading

0 comments on commit 8a08a9d

Please sign in to comment.