fix(releases): max downloads per hour (#883)

* fix(releases): max downloads per hour

* refactor: release processing

* compare apples to apples (#884)

* from rocketships back to apples

* Update internal/database/filter.go

* cast me to the

* keep your eye on the case

---------

Co-authored-by: Kyle Sanderson <kyle.leet@gmail.com>
This commit is contained in:
ze0s 2023-04-29 21:52:49 +02:00 committed by GitHub
parent da5492febb
commit ef3445cbed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 139 additions and 107 deletions

View file

@ -306,35 +306,11 @@ func (r *FilterRepo) FindByID(ctx context.Context, filterID int) (*domain.Filter
}
// FindByIndexerIdentifier find active filters with active indexer only
func (r *FilterRepo) FindByIndexerIdentifier(indexer string) ([]domain.Filter, error) {
ctx := context.TODO()
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return nil, errors.Wrap(err, "error begin transaction")
}
defer tx.Rollback()
filters, err := r.findByIndexerIdentifier(ctx, tx, indexer)
if err != nil {
return nil, err
}
for i, filter := range filters {
downloads, err := r.attachDownloadsByFilter(ctx, tx, filter.ID)
if err != nil {
continue
}
filters[i].Downloads = downloads
}
if err := tx.Commit(); err != nil {
return nil, errors.Wrap(err, "error finding filter by identifier")
}
return filters, nil
func (r *FilterRepo) FindByIndexerIdentifier(ctx context.Context, indexer string) ([]domain.Filter, error) {
return r.findByIndexerIdentifier(ctx, indexer)
}
func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexer string) ([]domain.Filter, error) {
func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, indexer string) ([]domain.Filter, error) {
queryBuilder := r.db.squirrel.
Select(
"f.id",
@ -416,7 +392,7 @@ func (r *FilterRepo) findByIndexerIdentifier(ctx context.Context, tx *Tx, indexe
return nil, errors.Wrap(err, "error building query")
}
rows, err := tx.QueryContext(ctx, query, args...)
rows, err := r.db.handler.QueryContext(ctx, query, args...)
if err != nil {
return nil, errors.Wrap(err, "error executing query")
}
@ -1052,25 +1028,25 @@ func (r *FilterRepo) Delete(ctx context.Context, filterID int) error {
return nil
}
func (r *FilterRepo) attachDownloadsByFilter(ctx context.Context, tx *Tx, filterID int) (*domain.FilterDownloads, error) {
func (r *FilterRepo) GetDownloadsByFilterId(ctx context.Context, filterID int) (*domain.FilterDownloads, error) {
if r.db.Driver == "sqlite" {
return r.downloadsByFilterSqlite(ctx, tx, filterID)
return r.downloadsByFilterSqlite(ctx, filterID)
}
return r.downloadsByFilterPostgres(ctx, tx, filterID)
return r.downloadsByFilterPostgres(ctx, filterID)
}
func (r *FilterRepo) downloadsByFilterSqlite(ctx context.Context, tx *Tx, filterID int) (*domain.FilterDownloads, error) {
func (r *FilterRepo) downloadsByFilterSqlite(ctx context.Context, filterID int) (*domain.FilterDownloads, error) {
query := `SELECT
IFNULL(SUM(CASE WHEN release_action_status.timestamp >= strftime('%Y-%m-%d %H:00:00', datetime('now','localtime')) THEN 1 ELSE 0 END),0) as "hour_count",
IFNULL(SUM(CASE WHEN release_action_status.timestamp >= datetime('now', 'localtime', 'start of day') THEN 1 ELSE 0 END),0) as "day_count",
IFNULL(SUM(CASE WHEN release_action_status.timestamp >= datetime('now', 'localtime', 'weekday 0', '-7 days') THEN 1 ELSE 0 END),0) as "week_count",
IFNULL(SUM(CASE WHEN release_action_status.timestamp >= datetime('now', 'localtime', 'start of month') THEN 1 ELSE 0 END),0) as "month_count",
count(*) as "total_count"
COUNT(CASE WHEN CAST(strftime('%s', datetime(release_action_status.timestamp, 'localtime')) AS INTEGER) >= CAST(strftime('%s', strftime('%Y-%m-%dT%H:00:00', datetime('now','localtime'))) AS INTEGER) THEN 1 END) as "hour_count",
COUNT(CASE WHEN CAST(strftime('%s', datetime(release_action_status.timestamp, 'localtime')) AS INTEGER) >= CAST(strftime('%s', datetime('now', 'localtime', 'start of day')) AS INTEGER) THEN 1 END) as "day_count",
COUNT(CASE WHEN CAST(strftime('%s', datetime(release_action_status.timestamp, 'localtime')) AS INTEGER) >= CAST(strftime('%s', datetime('now', 'localtime', 'weekday 0', '-7 days', 'start of day')) AS INTEGER) THEN 1 END) as "week_count",
COUNT(CASE WHEN CAST(strftime('%s', datetime(release_action_status.timestamp, 'localtime')) AS INTEGER) >= CAST(strftime('%s', datetime('now', 'localtime', 'start of month')) AS INTEGER) THEN 1 END) as "month_count",
COUNT(*) as "total_count"
FROM release_action_status
WHERE release_action_status.status = 'PUSH_APPROVED' AND release_action_status.filter_id = ?;`
WHERE (release_action_status.status = 'PUSH_APPROVED' OR release_action_status.status = 'PENDING') AND release_action_status.filter_id = ?;`
row := tx.QueryRowContext(ctx, query, filterID)
row := r.db.handler.QueryRowContext(ctx, query, filterID)
if err := row.Err(); err != nil {
return nil, errors.Wrap(err, "error executing query")
}
@ -1086,7 +1062,7 @@ WHERE release_action_status.status = 'PUSH_APPROVED' AND release_action_status.f
return &f, nil
}
func (r *FilterRepo) downloadsByFilterPostgres(ctx context.Context, tx *Tx, filterID int) (*domain.FilterDownloads, error) {
func (r *FilterRepo) downloadsByFilterPostgres(ctx context.Context, filterID int) (*domain.FilterDownloads, error) {
query := `SELECT
COALESCE(SUM(CASE WHEN release_action_status.timestamp >= date_trunc('hour', CURRENT_TIMESTAMP) THEN 1 ELSE 0 END),0) as "hour_count",
COALESCE(SUM(CASE WHEN release_action_status.timestamp >= date_trunc('day', CURRENT_DATE) THEN 1 ELSE 0 END),0) as "day_count",
@ -1096,7 +1072,7 @@ func (r *FilterRepo) downloadsByFilterPostgres(ctx context.Context, tx *Tx, filt
FROM release_action_status
WHERE release_action_status.status = 'PUSH_APPROVED' AND release_action_status.filter_id = $1;`
row := tx.QueryRowContext(ctx, query, filterID)
row := r.db.handler.QueryRowContext(ctx, query, filterID)
if err := row.Err(); err != nil {
return nil, errors.Wrap(err, "error executing query")
}

View file

@ -54,23 +54,22 @@ func (repo *ReleaseRepo) Store(ctx context.Context, r *domain.Release) (*domain.
return r, nil
}
func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain.ReleaseActionStatus) error {
if a.ID != 0 {
func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, status *domain.ReleaseActionStatus) error {
if status.ID != 0 {
queryBuilder := repo.db.squirrel.
Update("release_action_status").
Set("status", a.Status).
Set("rejections", pq.Array(a.Rejections)).
Set("timestamp", a.Timestamp).
Where(sq.Eq{"id": a.ID}).
Where(sq.Eq{"release_id": a.ReleaseID})
Set("status", status.Status).
Set("rejections", pq.Array(status.Rejections)).
Set("timestamp", status.Timestamp.Format(time.RFC3339)).
Where(sq.Eq{"id": status.ID}).
Where(sq.Eq{"release_id": status.ReleaseID})
query, args, err := queryBuilder.ToSql()
if err != nil {
return errors.Wrap(err, "error building query")
}
_, err = repo.db.handler.ExecContext(ctx, query, args...)
if err != nil {
if _, err = repo.db.handler.ExecContext(ctx, query, args...); err != nil {
return errors.Wrap(err, "error executing query")
}
@ -78,21 +77,20 @@ func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, a *domain
queryBuilder := repo.db.squirrel.
Insert("release_action_status").
Columns("status", "action", "type", "client", "filter", "filter_id", "rejections", "timestamp", "release_id").
Values(a.Status, a.Action, a.Type, a.Client, a.Filter, a.FilterID, pq.Array(a.Rejections), a.Timestamp, a.ReleaseID).
Values(status.Status, status.Action, status.Type, status.Client, status.Filter, status.FilterID, pq.Array(status.Rejections), status.Timestamp.Format(time.RFC3339), status.ReleaseID).
Suffix("RETURNING id").RunWith(repo.db.handler)
// return values
var retID int64
err := queryBuilder.QueryRowContext(ctx).Scan(&retID)
if err != nil {
if err := queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil {
return errors.Wrap(err, "error executing query")
}
a.ID = retID
status.ID = retID
}
repo.log.Trace().Msgf("release.store_release_action_status: %+v", a)
repo.log.Trace().Msgf("release.store_release_action_status: %+v", status)
return nil
}