Skip to content

Commit bf58a1b

Browse files
authored
GT-389 Async Client [V1] (#525)
1 parent 54b4515 commit bf58a1b

21 files changed

+875
-58
lines changed

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ services:
2727

2828
language: go
2929
go:
30-
- 1.20.5
30+
- 1.20.6
3131

3232
env:
3333
jobs:
@@ -44,7 +44,7 @@ env:
4444
- ARANGODB=gcr.io/gcr-for-testing/arangodb/enterprise-preview:3.11.1
4545
- GOIMAGE=gcr.io/gcr-for-testing/golang:1.20.5
4646
- ALPINE_IMAGE=gcr.io/gcr-for-testing/alpine:3.17
47-
- STARTER=gcr.io/gcr-for-testing/arangodb/arangodb-starter:0.15.7
47+
- STARTER=arangodb/arangodb-starter:latest
4848
- TEST_DISALLOW_UNKNOWN_FIELDS=false
4949

5050
before_script:

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Add support for getting license
55
- Add support for Raw Authentication in VST (support external jwt token as raw element)
66
- Fix race when using WithRawResponse/WithResponse context with agencyConnection
7+
- [V1] Async Client
78

89
## [1.6.0](https://github.com/arangodb/go-driver/tree/v1.6.0) (2023-05-30)
910
- Add ErrArangoDatabaseNotFound and IsExternalStorageError helper to v2

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ SCRIPTDIR := $(shell pwd)
66
CURR=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
77
ROOTDIR:=$(CURR)
88

9-
GOVERSION ?= 1.20.5
9+
GOVERSION ?= 1.20.6
1010
GOIMAGE ?= golang:$(GOVERSION)
1111
GOV2IMAGE ?= $(GOIMAGE)
1212
ALPINE_IMAGE ?= alpine:3.17

asyncjob.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package driver
22+
23+
import (
24+
"context"
25+
"time"
26+
)
27+
28+
type ClientAsyncJob interface {
29+
AsyncJob() AsyncJobService
30+
}
31+
32+
// AsyncJobService https://www.arangodb.com/docs/devel/http/jobs.html
33+
type AsyncJobService interface {
34+
// List Returns the ids of job results with a specific status
35+
List(ctx context.Context, jobType AsyncJobStatusType, opts *AsyncJobListOptions) ([]string, error)
36+
// Status Returns the status of a specific job
37+
Status(ctx context.Context, jobID string) (AsyncJobStatusType, error)
38+
// Cancel Cancels a specific async job
39+
Cancel(ctx context.Context, jobID string) (bool, error)
40+
// Delete Deletes async job result
41+
Delete(ctx context.Context, deleteType AsyncJobDeleteType, opts *AsyncJobDeleteOptions) (bool, error)
42+
}
43+
44+
type AsyncJobStatusType string
45+
46+
const (
47+
JobDone AsyncJobStatusType = "done"
48+
JobPending AsyncJobStatusType = "pending"
49+
)
50+
51+
type AsyncJobListOptions struct {
52+
// Count The maximum number of ids to return per call.
53+
// If not specified, a server-defined maximum value will be used.
54+
Count int `json:"count,omitempty"`
55+
}
56+
57+
type AsyncJobDeleteType string
58+
59+
const (
60+
DeleteAllJobs AsyncJobDeleteType = "all"
61+
DeleteExpiredJobs AsyncJobDeleteType = "expired"
62+
DeleteSingleJob AsyncJobDeleteType = "single"
63+
)
64+
65+
type AsyncJobDeleteOptions struct {
66+
// JobID The id of the job to delete. Works only if type is set to 'single'.
67+
JobID string `json:"id,omitempty"`
68+
69+
// Stamp A Unix timestamp specifying the expiration threshold for when the type is set to 'expired'.
70+
Stamp time.Time `json:"stamp,omitempty"`
71+
}

asyncjob_impl.go

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package driver
22+
23+
import (
24+
"context"
25+
"fmt"
26+
"path"
27+
)
28+
29+
const asyncJobAPI = "_api/job"
30+
31+
type clientAsyncJob struct {
32+
conn Connection
33+
}
34+
35+
func (c *client) AsyncJob() AsyncJobService {
36+
return &clientAsyncJob{
37+
conn: c.conn,
38+
}
39+
}
40+
41+
func (c *clientAsyncJob) List(ctx context.Context, jobType AsyncJobStatusType, opts *AsyncJobListOptions) ([]string, error) {
42+
req, err := c.conn.NewRequest("GET", path.Join(asyncJobAPI, pathEscape(string(jobType))))
43+
if err != nil {
44+
return nil, WithStack(err)
45+
}
46+
47+
if opts != nil && opts.Count != 0 {
48+
req.SetQuery("count", fmt.Sprintf("%d", opts.Count))
49+
}
50+
51+
var rawResponse []byte
52+
ctx = WithRawResponse(ctx, &rawResponse)
53+
54+
resp, err := c.conn.Do(ctx, req)
55+
if err != nil {
56+
return nil, WithStack(err)
57+
}
58+
if err := resp.CheckStatus(200); err != nil {
59+
return nil, WithStack(err)
60+
}
61+
62+
var result []string
63+
if err = c.conn.Unmarshal(rawResponse, &result); err != nil {
64+
return nil, err
65+
}
66+
67+
return result, nil
68+
}
69+
70+
func (c *clientAsyncJob) Status(ctx context.Context, jobID string) (AsyncJobStatusType, error) {
71+
req, err := c.conn.NewRequest("GET", path.Join(asyncJobAPI, pathEscape(jobID)))
72+
if err != nil {
73+
return "nil", WithStack(err)
74+
}
75+
76+
resp, err := c.conn.Do(ctx, req)
77+
if err != nil {
78+
return "", WithStack(err)
79+
}
80+
81+
switch resp.StatusCode() {
82+
case 200:
83+
return JobDone, nil
84+
case 204:
85+
return JobPending, nil
86+
default:
87+
return "", WithStack(resp.CheckStatus(200, 204))
88+
}
89+
}
90+
91+
type cancelResponse struct {
92+
Result bool `json:"result"`
93+
}
94+
95+
func (c *clientAsyncJob) Cancel(ctx context.Context, jobID string) (bool, error) {
96+
req, err := c.conn.NewRequest("PUT", path.Join(asyncJobAPI, pathEscape(jobID), "cancel"))
97+
if err != nil {
98+
return false, WithStack(err)
99+
}
100+
101+
resp, err := c.conn.Do(ctx, req)
102+
if err != nil {
103+
return false, WithStack(err)
104+
}
105+
106+
if err := resp.CheckStatus(200); err != nil {
107+
return false, WithStack(err)
108+
}
109+
110+
var data cancelResponse
111+
if err := resp.ParseBody("", &data); err != nil {
112+
return false, WithStack(err)
113+
}
114+
return data.Result, nil
115+
}
116+
117+
type deleteResponse struct {
118+
Result bool `json:"result"`
119+
}
120+
121+
func (c *clientAsyncJob) Delete(ctx context.Context, deleteType AsyncJobDeleteType, opts *AsyncJobDeleteOptions) (bool, error) {
122+
p := ""
123+
switch deleteType {
124+
case DeleteAllJobs:
125+
p = path.Join(asyncJobAPI, pathEscape(string(deleteType)))
126+
case DeleteExpiredJobs:
127+
if opts == nil || opts.Stamp.IsZero() {
128+
return false, WithStack(InvalidArgumentError{Message: "stamp must be set when deleting expired jobs"})
129+
}
130+
p = path.Join(asyncJobAPI, pathEscape(string(deleteType)))
131+
case DeleteSingleJob:
132+
if opts == nil || opts.JobID == "" {
133+
return false, WithStack(InvalidArgumentError{Message: "jobID must be set when deleting a single job"})
134+
}
135+
p = path.Join(asyncJobAPI, pathEscape(opts.JobID))
136+
}
137+
138+
req, err := c.conn.NewRequest("DELETE", p)
139+
if err != nil {
140+
return false, WithStack(err)
141+
}
142+
143+
if deleteType == DeleteExpiredJobs {
144+
req.SetQuery("stamp", fmt.Sprintf("%d", opts.Stamp.Unix()))
145+
}
146+
147+
resp, err := c.conn.Do(ctx, req)
148+
if err != nil {
149+
return false, WithStack(err)
150+
}
151+
152+
if err := resp.CheckStatus(200); err != nil {
153+
return false, WithStack(err)
154+
}
155+
156+
var data deleteResponse
157+
if err := resp.ParseBody("", &data); err != nil {
158+
return false, WithStack(err)
159+
}
160+
return data.Result, nil
161+
}

client.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -52,29 +52,33 @@ type Client interface {
5252
// Connection returns the connection used by this client
5353
Connection() Connection
5454

55-
// Database functions
55+
// ClientDatabases - Database functions
5656
ClientDatabases
5757

58-
// User functions
58+
// ClientUsers - User functions
5959
ClientUsers
6060

61-
// Cluster functions
61+
// ClientCluster - Cluster functions
6262
ClientCluster
6363

64-
// Individual server information functions
64+
// ClientServerInfo - Individual server information functions
6565
ClientServerInfo
6666

67-
// Server/cluster administration functions
67+
// ClientServerAdmin - Server/cluster administration functions
6868
ClientServerAdmin
6969

70-
// Replication functions
70+
// ClientReplication - Replication functions
7171
ClientReplication
7272

73-
// Backup functions
73+
// ClientAdminBackup - Backup functions
7474
ClientAdminBackup
7575

76+
// ClientFoxx - Foxx functions
7677
ClientFoxx
7778

79+
// ClientAsyncJob - Asynchronous job functions
80+
ClientAsyncJob
81+
7882
ClientLog
7983
}
8084

client_impl.go

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func NewClient(config ClientConfig) (Client, error) {
4242
return nil, WithStack(err)
4343
}
4444
}
45+
4546
c := &client{
4647
conn: conn,
4748
}

client_server_info.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2018=2023 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -17,8 +17,6 @@
1717
//
1818
// Copyright holder is ArangoDB GmbH, Cologne, Germany
1919
//
20-
// Author Ewout Prangsma
21-
//
2220

2321
package driver
2422

@@ -35,7 +33,7 @@ type ClientServerInfo interface {
3533
// ServerRole returns the role of the server that answers the request.
3634
ServerRole(ctx context.Context) (ServerRole, error)
3735

38-
// Gets the ID of this server in the cluster.
36+
// ServerID Gets the ID of this server in the cluster.
3937
// An error is returned when calling this to a server that is not part of a cluster.
4038
ServerID(ctx context.Context) (string, error)
4139
}

0 commit comments

Comments
 (0)