Skip to content

Commit 6a699fc

Browse files
committed
Move code to pkg and cmd
1 parent 6bec219 commit 6a699fc

File tree

7 files changed

+227
-76
lines changed

7 files changed

+227
-76
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-include .env
2+
3+
VERSION := $(shell git describe --tags)
4+
5+
compile:
6+
go build -o pg-ping -ldflags "-s -w -X main.version=$(VERSION)" main.go

cmd/root.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
8+
"github.com/thecasualcoder/pg-ping/pkg/pg"
9+
"github.com/urfave/cli"
10+
)
11+
12+
// Execute the app
13+
func Execute(app *cli.App) error {
14+
app.Name = "pg-ping"
15+
app.Usage = "Ping your postgres continously"
16+
app.Action = run
17+
app.Flags = []cli.Flag{
18+
cli.BoolFlag{
19+
Name: "once",
20+
Usage: "Ping only once and quit",
21+
EnvVar: "PGPING_ONCE",
22+
},
23+
cli.BoolFlag{
24+
Name: "debug",
25+
Usage: "Print debug logs",
26+
EnvVar: "PGPING_DEBUG",
27+
},
28+
cli.StringFlag{
29+
Name: "username, U",
30+
Usage: "Username to connect to postgres",
31+
EnvVar: "PGPING_USERNAME",
32+
},
33+
cli.StringFlag{
34+
Name: "password, p",
35+
Usage: "Password to connect to postgres",
36+
EnvVar: "PGPING_PASSWORD",
37+
},
38+
cli.StringFlag{
39+
Name: "host, h",
40+
Usage: "Host of postgres server",
41+
EnvVar: "PGPING_HOST",
42+
},
43+
cli.StringFlag{
44+
Name: "dbname, d",
45+
Usage: "DBName to connect to",
46+
EnvVar: "PGPING_DBNAME",
47+
},
48+
cli.IntFlag{
49+
Name: "frequency, f",
50+
Usage: "Frequency to ping",
51+
EnvVar: "PGPING_FREQUENCY_IN_MS",
52+
},
53+
cli.StringFlag{
54+
Name: "query, c",
55+
Usage: "Query to run",
56+
EnvVar: "PGPING_QUERY",
57+
Value: "SELECT 1",
58+
},
59+
}
60+
return app.Run(os.Args)
61+
}
62+
63+
func run(c *cli.Context) error {
64+
if len(c.Args()) > 0 {
65+
cli.ShowAppHelp(c)
66+
return fmt.Errorf("args are not allowed")
67+
}
68+
conf := pg.Config{
69+
Username: c.String("username"),
70+
Password: c.String("password"),
71+
Host: c.String("host"),
72+
DBName: c.String("dbname"),
73+
FrequencyInMS: int32(c.Int("frequency")),
74+
Query: c.String("query"),
75+
}
76+
77+
encoder := json.NewEncoder(os.Stdout)
78+
79+
if c.BoolT("debug") {
80+
encoder.Encode(conf)
81+
}
82+
83+
db, err := pg.NewDB(conf)
84+
if err != nil {
85+
return err
86+
}
87+
defer db.Close()
88+
89+
var resultChan chan pg.SQLResult
90+
91+
if c.BoolT("once") {
92+
resultChan = db.PingOnce()
93+
} else {
94+
resultChan = db.Ping()
95+
}
96+
97+
for r := range resultChan {
98+
encoder.Encode(r)
99+
}
100+
101+
return nil
102+
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
module pg-ping
1+
module github.com/thecasualcoder/pg-ping
22

33
go 1.12
44

55
require (
6-
github.com/kelseyhightower/envconfig v1.3.0
76
github.com/lib/pq v1.0.0
7+
github.com/urfave/cli v1.20.0
88
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM=
2-
github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
31
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
42
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
3+
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
4+
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=

main.go

Lines changed: 14 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,28 @@
11
package main
22

33
import (
4-
"context"
5-
"database/sql"
6-
"encoding/json"
7-
"log"
4+
"fmt"
85
"os"
9-
"time"
106

11-
"github.com/kelseyhightower/envconfig"
12-
_ "github.com/lib/pq"
7+
"github.com/thecasualcoder/pg-ping/cmd"
8+
"github.com/urfave/cli"
139
)
1410

15-
func main() {
16-
var conf PGConfig
17-
err := envconfig.Process("PGPING", &conf)
18-
if err != nil {
19-
log.Fatal(err)
20-
}
21-
22-
if conf.Debug {
23-
json.NewEncoder(os.Stdout).Encode(conf)
24-
}
11+
var version string
2512

26-
db, err := sql.Open("postgres", conf.ConnStr())
27-
if err != nil {
28-
log.Fatal(err)
29-
}
30-
defer db.Close()
31-
32-
ticker := time.NewTicker(conf.GetFrequency())
33-
encoder := json.NewEncoder(os.Stdout)
34-
for range ticker.C {
35-
encoder.Encode(executeQuery(db, conf.GetQuery()))
36-
}
37-
}
13+
const defaultVersion = "dev"
3814

39-
// SQLResult tracks sql response and time taken
40-
type SQLResult struct {
41-
Value string
42-
TimeTakenInMS float64
43-
Failed bool
44-
FailureMessage string
45-
}
46-
47-
func executeQuery(db *sql.DB, query string) SQLResult {
48-
res := SQLResult{}
49-
50-
ctx, cancelFunc := context.WithCancel(context.Background())
51-
tenSecondTimer := time.NewTimer(10 * time.Second)
52-
go func() {
53-
<-tenSecondTimer.C
54-
cancelFunc()
55-
}()
56-
57-
start := time.Now()
58-
rows, err := db.QueryContext(ctx, query)
59-
res.TimeTakenInMS = time.Since(start).Seconds() * 1000
60-
61-
if err != nil {
62-
res.Failed = true
63-
res.FailureMessage = err.Error()
64-
return res
15+
func main() {
16+
var app = cli.NewApp()
17+
if version == "" {
18+
version = defaultVersion
6519
}
66-
defer rows.Close()
20+
app.Version = version
6721

68-
for rows.Next() {
69-
var name string
70-
if err := rows.Scan(&name); err != nil {
71-
res.Failed = true
72-
res.FailureMessage = err.Error()
73-
return res
74-
}
22+
cli.HelpFlag = cli.BoolFlag{Name: "help"}
7523

76-
res.Value = name
24+
if err := cmd.Execute(app); err != nil {
25+
fmt.Fprintf(os.Stderr, "pg-ping failed: %v\n", err)
26+
os.Exit(1)
7727
}
78-
79-
return res
8028
}

pg_config.go renamed to pkg/pg/config.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
package main
1+
package pg
22

33
import (
44
"fmt"
55
"time"
66
)
77

8-
// PGConfig contains configurations to connect to a PG database
9-
type PGConfig struct {
8+
// Config contains configurations to connect to a PG database
9+
type Config struct {
1010
Username string
1111
Password string
1212
Host string
@@ -17,12 +17,12 @@ type PGConfig struct {
1717
}
1818

1919
// ConnStr returns a connection string to connect to postgres
20-
func (c *PGConfig) ConnStr() string {
20+
func (c *Config) ConnStr() string {
2121
return fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable", c.Username, c.Password, c.Host, c.DBName)
2222
}
2323

2424
// GetQuery returns the query to use to ping
25-
func (c *PGConfig) GetQuery() string {
25+
func (c *Config) GetQuery() string {
2626
if c.Query == "" {
2727
return "select 1"
2828
}
@@ -31,7 +31,7 @@ func (c *PGConfig) GetQuery() string {
3131
}
3232

3333
// GetFrequency returns the frequence in MS in which the query should be run
34-
func (c *PGConfig) GetFrequency() time.Duration {
34+
func (c *Config) GetFrequency() time.Duration {
3535
if c.FrequencyInMS == 0 {
3636
return time.Second
3737
}

pkg/pg/db.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package pg
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"time"
7+
8+
_ "github.com/lib/pq"
9+
)
10+
11+
// DB represents a pingable DB
12+
type DB struct {
13+
db *sql.DB
14+
conf Config
15+
}
16+
17+
// NewDB creates a new DB connection
18+
func NewDB(conf Config) (*DB, error) {
19+
db, err := sql.Open("postgres", conf.ConnStr())
20+
if err != nil {
21+
return nil, err
22+
}
23+
return &DB{db: db, conf: conf}, nil
24+
}
25+
26+
// Close a pingable DB
27+
func (db *DB) Close() error {
28+
return db.db.Close()
29+
}
30+
31+
// PingOnce will execute query only once
32+
func (db *DB) PingOnce() chan SQLResult {
33+
result := make(chan SQLResult, 1)
34+
go func() {
35+
result <- executeQuery(db.db, db.conf.GetQuery())
36+
close(result)
37+
}()
38+
return result
39+
}
40+
41+
// Ping will execute query indefinitely
42+
func (db *DB) Ping() chan SQLResult {
43+
result := make(chan SQLResult, 10)
44+
go func() {
45+
ticker := time.NewTicker(db.conf.GetFrequency())
46+
for range ticker.C {
47+
result <- executeQuery(db.db, db.conf.GetQuery())
48+
}
49+
close(result)
50+
}()
51+
return result
52+
}
53+
54+
// SQLResult tracks sql response and time taken
55+
type SQLResult struct {
56+
Value string
57+
TimeTakenInMS float64
58+
Failed bool
59+
FailureMessage string
60+
}
61+
62+
func executeQuery(db *sql.DB, query string) SQLResult {
63+
res := SQLResult{}
64+
65+
ctx, cancelFunc := context.WithCancel(context.Background())
66+
tenSecondTimer := time.NewTimer(10 * time.Second)
67+
go func() {
68+
<-tenSecondTimer.C
69+
cancelFunc()
70+
}()
71+
72+
start := time.Now()
73+
rows, err := db.QueryContext(ctx, query)
74+
res.TimeTakenInMS = time.Since(start).Seconds() * 1000
75+
76+
if err != nil {
77+
res.Failed = true
78+
res.FailureMessage = err.Error()
79+
return res
80+
}
81+
defer rows.Close()
82+
83+
for rows.Next() {
84+
var name string
85+
if err := rows.Scan(&name); err != nil {
86+
res.Failed = true
87+
res.FailureMessage = err.Error()
88+
return res
89+
}
90+
91+
res.Value = name
92+
}
93+
94+
return res
95+
}

0 commit comments

Comments
 (0)