Compare commits

...

8 Commits

15 changed files with 130 additions and 36 deletions

37
.air.toml Normal file
View File

@@ -0,0 +1,37 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
kill_delay = "0s"
log = "build-errors.log"
send_interrupt = false
stop_on_error = true
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false

View File

@@ -0,0 +1,6 @@
groups:
- name: DemoAlerts
rules:
- alert: InstanceDown
expr: up{job="services"} < 1
for: 5m

View File

@@ -0,0 +1,17 @@
global:
scrape_interval: 30s
scrape_timeout: 10s
rule_files:
- alert.yml
scrape_configs:
- job_name: services
metrics_path: /metrics
static_configs:
- targets:
- 'prometheus:9090'
- job_name: 'file_ds'
file_sd_configs:
- files:
- targets.json

View File

@@ -0,0 +1,10 @@
[
{
"targets": [
"api:9091"
],
"labels": {
"job": "5f11-api"
}
}
]

1
.gitignore vendored
View File

@@ -23,3 +23,4 @@ go.work
# Artefacts # Artefacts
5feet11 5feet11
tmp

View File

@@ -8,30 +8,29 @@ info (
type ( type (
ExpandReq { ExpandReq {
Snowflake string `path:"snowflake"` ID string `path:"id"`
} }
ExpandResp { ExpandResp {
RedirectUrl string `json:"redirectUrl"` LongUrl string `json:"longUrl"`
} }
) )
type ( type (
ShortenReq { ShortenReq {
RedirectUrl string `json:"redirectUrl"` LongUrl string `json:"longUrl"`
Secret string `json:"secret,optional"` ExpiresAfter int64 `json:"expiresAfter,optional"`
ExpiresIn int64 `json:"expiresIn,optional"`
} }
ShortenResp { ShortenResp {
Id string `json:"id"` ID string `json:"id"`
} }
) )
service fivefeeteleven-api { service fivefeeteleven-api {
@handler ExpandUrl @handler ExpandUrl
get /:snowflake(ExpandReq) returns(ExpandResp) get /:id(ExpandReq) returns(ExpandResp)
@handler ShortenUrl @handler ShortenUrl
post /redirect(ShortenReq) returns(ShortenResp) post /redirect(ShortenReq) returns(ShortenResp)
} }

View File

@@ -4,8 +4,26 @@ services:
scylla: scylla:
image: scylladb/scylla image: scylladb/scylla
ports: ports:
- "7000:7000" - 7000:7000
- "7001:7001" - 7001:7001
- "9042:9042" - 9042:9042
- "9160:9160" - 9160:9160
- "10000:10000" - 10000:10000
prometheus:
image: prom/prometheus:v2.30.3
ports:
- 9090:9090
volumes:
- .docker/prometheus:/etc/prometheus
- prometheus-data:/prometheus
command: --web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml
# api:
# build:
# context: .
# ports:
# - 5111:5111
# depends_on:
# - scylla
volumes:
prometheus-data:

View File

@@ -4,4 +4,8 @@ Host: 0.0.0.0
Port: 5111 Port: 5111
ScyllaDB: ScyllaDB:
Hosts: Hosts:
- "localhost" - localhost
# Prometheus:
# Host: 0.0.0.0
# Port: 9091
# Path: /metrics

View File

@@ -4,13 +4,12 @@ import "github.com/scylladb/gocqlx/v2/table"
var UrlTable = table.New(table.Metadata{ var UrlTable = table.New(table.Metadata{
Name: "fivefeeteleven.urls", Name: "fivefeeteleven.urls",
Columns: []string{"id", "redirect_url", "secret"}, Columns: []string{"id", "long_url"},
PartKey: []string{"id"}, PartKey: []string{"id"},
SortKey: []string{}, SortKey: []string{},
}) })
type UrlModel struct { type UrlModel struct {
Id string ID string
RedirectUrl string LongUrl string
Secret *string
} }

View File

@@ -15,8 +15,7 @@ func Seed(session gocqlx.Session) error {
err = session.ExecStmt(` err = session.ExecStmt(`
CREATE TABLE IF NOT EXISTS fivefeeteleven.urls ( CREATE TABLE IF NOT EXISTS fivefeeteleven.urls (
id text PRIMARY KEY, id text PRIMARY KEY,
redirect_url text, long_url text
secret text
)`) )`)
if err != nil { if err != nil {

View File

@@ -23,7 +23,7 @@ func ExpandUrlHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
if err != nil { if err != nil {
httpx.Error(w, err) httpx.Error(w, err)
} else { } else {
http.Redirect(w, r, resp.RedirectUrl, http.StatusTemporaryRedirect) http.Redirect(w, r, resp.LongUrl, http.StatusTemporaryRedirect)
} }
} }
} }

View File

@@ -14,7 +14,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
[]rest.Route{ []rest.Route{
{ {
Method: http.MethodGet, Method: http.MethodGet,
Path: "/:snowflake", Path: "/:id",
Handler: ExpandUrlHandler(serverCtx), Handler: ExpandUrlHandler(serverCtx),
}, },
{ {

View File

@@ -26,8 +26,8 @@ func NewExpandUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ExpandU
} }
func (l *ExpandUrlLogic) ExpandUrl(req *types.ExpandReq) (resp *types.ExpandResp, err error) { func (l *ExpandUrlLogic) ExpandUrl(req *types.ExpandReq) (resp *types.ExpandResp, err error) {
queryUrl := db.UrlTable.SelectBuilder("redirect_url").Query(l.svcCtx.DB) queryUrl := db.UrlTable.SelectBuilder("long_url").Query(l.svcCtx.DB)
queryUrl.BindStruct(db.UrlModel{Id: req.Snowflake}) queryUrl.BindStruct(db.UrlModel{ID: req.ID})
var urls []db.UrlModel var urls []db.UrlModel
if err := queryUrl.Select(&urls); err != nil { if err := queryUrl.Select(&urls); err != nil {
@@ -39,7 +39,7 @@ func (l *ExpandUrlLogic) ExpandUrl(req *types.ExpandReq) (resp *types.ExpandResp
} }
resp = &types.ExpandResp{ resp = &types.ExpandResp{
RedirectUrl: urls[0].RedirectUrl, LongUrl: urls[0].LongUrl,
} }
return resp, err return resp, err

View File

@@ -27,12 +27,17 @@ func NewShortenUrlLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Shorte
func (l *ShortenUrlLogic) ShortenUrl(req *types.ShortenReq) (resp *types.ShortenResp, err error) { func (l *ShortenUrlLogic) ShortenUrl(req *types.ShortenReq) (resp *types.ShortenResp, err error) {
id := l.svcCtx.Snowflake.Generate().Base58() id := l.svcCtx.Snowflake.Generate().Base58()
insertBuilder := db.UrlTable.InsertBuilder()
insertUrl := db.UrlTable.InsertBuilder().TTL(30 * time.Second).Query(l.svcCtx.DB) logx.Info(req.ExpiresAfter)
if req.ExpiresAfter != 0 {
insertBuilder.TTL(time.Second * time.Duration(req.ExpiresAfter))
}
insertUrl := insertBuilder.Query(l.svcCtx.DB)
insertUrl.BindStruct(db.UrlModel{ insertUrl.BindStruct(db.UrlModel{
Id: id, ID: id,
RedirectUrl: req.RedirectUrl, LongUrl: req.LongUrl,
Secret: &req.Secret,
}) })
if err := insertUrl.ExecRelease(); err != nil { if err := insertUrl.ExecRelease(); err != nil {
@@ -40,7 +45,7 @@ func (l *ShortenUrlLogic) ShortenUrl(req *types.ShortenReq) (resp *types.Shorten
} }
resp = &types.ShortenResp{ resp = &types.ShortenResp{
Id: id, ID: id,
} }
return resp, nil return resp, nil
} }

View File

@@ -2,19 +2,18 @@
package types package types
type ExpandReq struct { type ExpandReq struct {
Snowflake string `path:"snowflake"` ID string `path:"id"`
} }
type ExpandResp struct { type ExpandResp struct {
RedirectUrl string `json:"redirectUrl"` LongUrl string `json:"longUrl"`
} }
type ShortenReq struct { type ShortenReq struct {
RedirectUrl string `json:"redirectUrl"` LongUrl string `json:"longUrl"`
Secret string `json:"secret,optional"` ExpiresAfter int64 `json:"expiresAfter,optional"`
ExpiresIn int64 `json:"expiresIn,optional"`
} }
type ShortenResp struct { type ShortenResp struct {
Id string `json:"id"` ID string `json:"id"`
} }