Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background API #971

Merged
merged 66 commits into from
Jan 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
caf1cf1
every go routine needs to have its own collection factory
Nov 18, 2016
af48597
Removed obsolete RWMutexes
Nov 18, 2016
ae8910d
Database changes of resources need to be atomic
Nov 18, 2016
483beef
db batch may not be a global resource
Nov 21, 2016
7476937
Solving progress not safe issue for api
Nov 25, 2016
5fc97f1
Fixed not running tests
Nov 28, 2016
f0ea727
Add task api and resource locking ability
May 22, 2017
92b30a7
Added mirror api based on task list
May 22, 2017
0268b10
Added gpg api so mirror updates are fully functional from api
May 22, 2017
67beea6
Combine publish list progress into one
May 17, 2018
0aa85a0
Add publish output progress counting remaining number of packages
May 17, 2018
1a3d7e3
Add db cleanup api
Jun 20, 2018
62bcc7f
log download retries
neolynx Jun 29, 2019
67eb248
api: allow renaming repos
neolynx Sep 26, 2020
2f937ef
fix gpg keys
neolynx Sep 28, 2020
93f6589
Use verifier from context
lbolla Jan 5, 2021
64893c1
api gpg: show gpg command
neolynx Oct 11, 2020
a051213
mirror: increase logging for easier debugging
lbolla May 4, 2021
759d517
mirror: interrupt goroutine when done
lbolla May 5, 2021
09a8647
mirror: add more logging
lbolla May 5, 2021
1ab367a
gpg: fix downloading multiple keys
neolynx Apr 1, 2021
d28c9b7
Sleep between retries to download from http
lbolla Jun 23, 2021
43c28ba
Cap delay to sleep to avoid overflow
lbolla Jun 25, 2021
236a8ad
Don't use transactions when direct db access is enough
lbolla Aug 24, 2021
4f0342b
Fix syntax error
lbolla Aug 24, 2021
273d028
Add new AUTHORS
lbolla Aug 26, 2021
220e45e
Configurable background task execution
lbolla Sep 8, 2021
4c5b40f
Use global async flag as fallback on per-request flag
lbolla Sep 14, 2021
2a0aacc
More informative return value for task.Process
lbolla Sep 20, 2021
02c11dc
Fix system tests
lbolla Sep 21, 2021
525b2a1
Fix indentation
lbolla Oct 27, 2021
94c173c
Fix rebase
lbolla Nov 2, 2021
1f36620
Fix unittests
lbolla Nov 2, 2021
f511731
Fix pure-go unittests
lbolla Nov 2, 2021
76963fb
Make truthy function less surprising
lbolla Dec 16, 2021
d196400
Use newer golangci-lint source as the former is abandoned.
ximon18 Jan 24, 2022
49f4945
Workaround differences in the GHA Ubuntu 18.04 environment compared t…
ximon18 Jan 24, 2022
786f8ca
Initial attempt at a GitHub Actions workflow to emulate the previousl…
ximon18 Jan 24, 2022
8f95474
Fix syntax error.
ximon18 Jan 24, 2022
d78e3b1
Matrix elements must be arrays.
ximon18 Jan 24, 2022
2e18eae
continue-on-error value must be a boolean
ximon18 Jan 24, 2022
58075e5
Disable testing against Go master for now.
ximon18 Jan 24, 2022
cace05d
golint: "Json" in func name should be "JSON".
ximon18 Jan 25, 2022
6672ef4
golint: "Json" in func name should be "JSON".
ximon18 Jan 25, 2022
4023020
govet: compose literal uses unkeyed fields
ximon18 Jan 25, 2022
356bc9f
govet: compose literal uses unkeyed fields
ximon18 Jan 25, 2022
303c011
Add a comment referring to the original Travis CI config from the new…
ximon18 Jan 25, 2022
63dc24c
govet: compose literal uses unkeyed fields
ximon18 Jan 25, 2022
01627e3
govet: compose literal uses unkeyed fields
ximon18 Jan 25, 2022
04bf92a
Fix linting errors
lbolla Jan 25, 2022
adf978e
Fix flake8 lint errors
lbolla Jan 25, 2022
e2d2a2d
Fix some failing system tests
lbolla Jan 25, 2022
60cdcba
Try to fix test failing on CI
lbolla Jan 25, 2022
4d62266
Temporarily skip test failing on CI
lbolla Jan 25, 2022
bd3dd23
Fix test after merge
lbolla Jan 26, 2022
27fac43
Trigger CI on every push
randombenj Jan 26, 2022
613003b
Build for newer go versions
randombenj Jan 26, 2022
1d51850
Silence unhelpful linter error
lbolla Jan 26, 2022
c764a62
Fix failing tests
lbolla Jan 26, 2022
bd8507c
Re-enable testing on go 1.17
lbolla Jan 26, 2022
dcb909d
Ignore dates in test
lbolla Jan 26, 2022
88c36d8
Typo correction in GHA workflow comment
ximon18 Jan 26, 2022
ca36bb5
Strip irrelevant lines from test output
lbolla Jan 26, 2022
67dfa02
Allow to check for empty output in tests
lbolla Jan 26, 2022
110dba4
Update minimum required go version
randombenj Jan 27, 2022
1e91e29
Only run system test with latest go version
randombenj Jan 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Based on https://github.com/aptly-dev/aptly/blob/master/.travis.yml

name: CI

on:
pull_request:
push:
branches:
- 'main'

defaults:
run:
# see: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell
shell: bash --noprofile --norc -eo pipefail -x {0}

env:
DEBIAN_FRONTEND: noninteractive

jobs:
build:
name: test
runs-on: ubuntu-18.04
continue-on-error: ${{ matrix.allow_failure }}
strategy:
fail-fast: true
matrix:
go: [1.14, 1.15, 1.16]
run_long_tests: [no]
allow_failure: [false]
include:
# Disable this for now as it's not clear how to select the latest master branch
# version of go using actions/setup-go@v2.
# - go: master
# run_long_tests: no
# allow_failure: true
- go: 1.17
run_long_tests: yes
allow_failure: false

env:
NO_FTP_ACCESS: yes
BOTO_CONFIG: /dev/null
GO111MODULE: "on"
GOPROXY: "https://proxy.golang.org"

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}

- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 2.7.17

- name: Install O/S packages
run: |
sudo apt-get update
sudo apt-get install -y python-virtualenv graphviz gnupg1 gnupg2 gpgv1 gpgv2 git gcc make

- name: Install Python packages
run: |
pip install six packaging appdirs
pip install -U pip setuptools
pip install -r system/requirements.txt

- name: Get aptly version
run: |
make version

- name: Make prepare
run: |
make prepare

- name: Make
env:
RUN_LONG_TESTS: ${{ matrix.run_long_tests }}
run: |
make
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ build/

pgp/keyrings/aptly2*.gpg
pgp/keyrings/aptly2*.gpg~
pgp/keyrings/.#*
15 changes: 6 additions & 9 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,17 @@ run:


linters:
enable-all: false
disable-all: true
enable:
- govet
- golint
- gofmt
- deadcode
- goconst
- gofmt
- goimports
- misspell
- govet
- ineffassign
- misspell
- revive
- staticcheck
- varcheck
- structcheck
- maligned
- varcheck
- vetshadow
- goconst
- interfacer
3 changes: 3 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ List of contributors, in chronological order:
* Raul Benencia (https://github.com/rul)
* Don Kuntz (https://github.com/dkuntz2)
* Joshua Colson (https://github.com/freakinhippie)
* Andre Roth (https://github.com/neolynx)
* Lorenzo Bolla (https://github.com/lbolla)
* Benj Fassbind (https://github.com/randombenj)
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ RUN_LONG_TESTS?=yes
all: modules test bench check system-test

prepare:
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.19.1
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.43.0

modules:
go mod download
Expand Down Expand Up @@ -79,3 +79,4 @@ version:
@echo $(VERSION)

.PHONY: man modules version release goxc

2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ If you would like to use nightly builds (unstable), please use following reposit

Binary executables (depends almost only on libc) are available for download from `GitHub Releases <https://github.com/aptly-dev/aptly/releases>`_.

If you have Go environment set up, you can build aptly from source by running (go 1.11+ required)::
If you have Go environment set up, you can build aptly from source by running (go 1.14+ required)::

git clone https://github.com/aptly-dev/aptly
cd aptly
Expand Down
140 changes: 98 additions & 42 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package api

import (
"fmt"
"log"
"net/http"
"sort"
"time"
"strconv"
"strings"

"github.com/aptly-dev/aptly/aptly"
"github.com/aptly-dev/aptly/deb"
"github.com/aptly-dev/aptly/query"
"github.com/aptly-dev/aptly/task"
"github.com/gin-gonic/gin"
)

Expand All @@ -35,49 +39,14 @@ type dbRequest struct {
err chan<- error
}

// Flushes all collections which cache in-memory objects
func flushColections() {
// lock everything to eliminate in-progress calls
r := context.CollectionFactory().RemoteRepoCollection()
r.Lock()
defer r.Unlock()

l := context.CollectionFactory().LocalRepoCollection()
l.Lock()
defer l.Unlock()

s := context.CollectionFactory().SnapshotCollection()
s.Lock()
defer s.Unlock()

p := context.CollectionFactory().PublishedRepoCollection()
p.Lock()
defer p.Unlock()

// all collections locked, flush them
context.CollectionFactory().Flush()
}

// Periodically flushes CollectionFactory to free up memory used by
// collections, flushing caches.
//
// Should be run in goroutine!
func cacheFlusher() {
ticker := time.Tick(15 * time.Minute)

for {
<-ticker

flushColections()
}
}
var dbRequests chan dbRequest

// Acquire database lock and release it when not needed anymore.
//
// Should be run in a goroutine!
func acquireDatabase(requests <-chan dbRequest) {
func acquireDatabase() {
clients := 0
for request := range requests {
for request := range dbRequests {
var err error

switch request.kind {
Expand All @@ -94,7 +63,6 @@ func acquireDatabase(requests <-chan dbRequest) {
case releasedb:
clients--
if clients == 0 {
flushColections()
err = context.CloseDatabase()
} else {
err = nil
Expand All @@ -105,12 +73,100 @@ func acquireDatabase(requests <-chan dbRequest) {
}
}

// Should be called before database access is needed in any api call.
// Happens per default for each api call. It is important that you run
// runTaskInBackground to run a task which accquire database.
// Important do not forget to defer to releaseDatabaseConnection
func acquireDatabaseConnection() error {
if dbRequests == nil {
return nil
}

errCh := make(chan error)
dbRequests <- dbRequest{acquiredb, errCh}

return <-errCh
}

// Release database connection when not needed anymore
func releaseDatabaseConnection() error {
if dbRequests == nil {
return nil
}

errCh := make(chan error)
dbRequests <- dbRequest{releasedb, errCh}
return <-errCh
}

// runs tasks in background. Acquires database connection first.
func runTaskInBackground(name string, resources []string, proc task.Process) (task.Task, *task.ResourceConflictError) {
return context.TaskList().RunTaskInBackground(name, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
err := acquireDatabaseConnection()

if err != nil {
return nil, err
}

defer releaseDatabaseConnection()
return proc(out, detail)
})
}

func truthy(value interface{}) bool {
if value == nil {
return false
}
switch value.(type) {
case string:
switch strings.ToLower(value.(string)) {
case "n", "no", "f", "false", "0", "off":
return false
default:
return true
}
case int:
return !(value.(int) == 0)
case bool:
return value.(bool)
}
return true
}

func maybeRunTaskInBackground(c *gin.Context, name string, resources []string, proc task.Process) {
// Run this task in background if configured globally or per-request
background := truthy(c.DefaultQuery("_async", strconv.FormatBool(context.Config().AsyncAPI)))
if background {
log.Println("Executing task asynchronously")
task, conflictErr := runTaskInBackground(name, resources, proc)
if conflictErr != nil {
c.AbortWithError(409, conflictErr)
return
}
c.JSON(202, task)
} else {
log.Println("Executing task synchronously")
out := context.Progress()
detail := task.Detail{}
retValue, err := proc(out, &detail)
if err != nil {
c.AbortWithError(retValue.Code, err)
return
}
if retValue != nil {
c.JSON(retValue.Code, retValue.Value)
} else {
c.JSON(http.StatusOK, nil)
}
}
}

// Common piece of code to show list of packages,
// with searching & details if requested
func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
func showPackages(c *gin.Context, reflist *deb.PackageRefList, collectionFactory *deb.CollectionFactory) {
result := []*deb.Package{}

list, err := deb.NewPackageListFromRefList(reflist, context.CollectionFactory().PackageCollection(), nil)
list, err := deb.NewPackageListFromRefList(reflist, collectionFactory.PackageCollection(), nil)
if err != nil {
c.AbortWithError(404, err)
return
Expand Down
Loading