Skip to content

Commit 912f109

Browse files
committed
feat: make job logic re-runnable
1 parent ddb1e8d commit 912f109

13 files changed

Lines changed: 110 additions & 109 deletions

File tree

config.yaml.example

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
USER_ID: "user-1234"
66
DATASET_ID: "aa-Dataset-abc"
77
DATASET_FOLDER: "DATASET_ABC"
8-
JOB_EXPECTED_NR_FILES: 0
98
CLIENT_ACCESS_TOKEN: "youraccesstoken"
109

1110
MAIL_ADDRESS: "myemail@example.com"

helpers/helpers.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212

1313
"github.com/NBISweden/sda-bpctl/cmd"
1414
"github.com/NBISweden/sda-bpctl/internal/config"
15-
"github.com/NBISweden/sda-bpctl/internal/models"
1615
"github.com/spf13/cobra"
1716
)
1817

@@ -146,16 +145,3 @@ func GetFileIDsPath(dataDirectory string, datasetFolder string) string {
146145
func GetStableIDsPath(dataDirectory string, datasetFolder string) string {
147146
return fmt.Sprintf("%s/%s-stableIDs.txt", dataDirectory, datasetFolder)
148147
}
149-
150-
func GetPathsForAccessionIDs(files []models.FileInfo, datasetFolder string) []string {
151-
var paths []string
152-
for _, f := range files {
153-
if f.Status == "verified" &&
154-
strings.Contains(f.InboxPath, datasetFolder) &&
155-
!strings.Contains(f.InboxPath, "PRIVATE") {
156-
paths = append(paths, f.InboxPath)
157-
}
158-
}
159-
slog.Info("files found for accession id creation", "files_found", len(paths))
160-
return paths
161-
}

helpers/templates/job.template.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ spec:
9595
- name: xml-data
9696
secret:
9797
defaultMode: 288
98-
secretName: {{ .JobName }}-xml-secret
98+
secretName: job-xml-secret
9999
{{- end }}
100100
- name: tls
101101
secret:

internal/accession/accession.go

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/NBISweden/sda-bpctl/helpers"
1515
"github.com/NBISweden/sda-bpctl/internal/client"
1616
"github.com/NBISweden/sda-bpctl/internal/config"
17+
"github.com/NBISweden/sda-bpctl/internal/models"
1718
"github.com/spf13/cobra"
1819
)
1920

@@ -51,17 +52,12 @@ var accessionCmd = &cobra.Command{
5152
}
5253
defer file.Close() //nolint:errcheck
5354

54-
files, err := api.GetUsersFilesWithPrefix()
55-
if err != nil {
56-
return err
57-
}
58-
59-
paths := helpers.GetPathsForAccessionIDs(files, datasetFolder)
55+
files, err := api.GetFilesWithStatus("verified")
6056
if dryRun {
6157
slog.Info("dry run enabled, no accession ids will be created")
6258
return nil
6359
}
64-
accessionIDs, err := postAccessionIDs(api, paths, userID)
60+
accessionIDs, err := postAccessionIDs(api, files, userID)
6561

6662
for _, accessionID := range accessionIDs {
6763
if _, err := file.WriteString(accessionID + "\n"); err != nil {
@@ -86,12 +82,7 @@ func init() {
8682

8783
func Run(api client.APIClient, datasetFolder string, userID string) ([]string, error) {
8884
slog.Info("starting accession")
89-
files, err := api.GetUsersFilesWithPrefix()
90-
if err != nil {
91-
return nil, err
92-
}
93-
94-
paths := helpers.GetPathsForAccessionIDs(files, datasetFolder)
85+
paths, err := api.GetFilesWithStatus("verified")
9586
accessionIDs, err := postAccessionIDs(api, paths, userID)
9687
if err != nil {
9788
return nil, err
@@ -101,17 +92,17 @@ func Run(api client.APIClient, datasetFolder string, userID string) ([]string, e
10192
return accessionIDs, nil
10293
}
10394

104-
func postAccessionIDs(api client.APIClient, paths []string, userID string) ([]string, error) {
95+
func postAccessionIDs(api client.APIClient, files []models.FileInfo, userID string) ([]string, error) {
10596
var accessionIDs []string
106-
for _, filepath := range paths {
97+
for _, file := range files {
10798
accessionID, err := generateAccessionID()
10899
if err != nil {
109100
return accessionIDs, err
110101
}
111102

112103
payload, err := json.Marshal(map[string]string{
113104
"accession_id": accessionID,
114-
"filepath": filepath,
105+
"filepath": file.InboxPath,
115106
"user": userID,
116107
})
117108
if err != nil {
@@ -128,7 +119,7 @@ func postAccessionIDs(api client.APIClient, paths []string, userID string) ([]st
128119
accessionIDs = append(accessionIDs, accessionID)
129120
}
130121

131-
slog.Info("accession IDs assigned", "nr_files", len(paths))
122+
slog.Info("accession IDs assigned", "nr_files", len(files))
132123
return accessionIDs, nil
133124
}
134125

internal/accession/accession_test.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ import (
99
"os"
1010
"path/filepath"
1111
"testing"
12+
"time"
1213

13-
"github.com/NBISweden/sda-bpctl/helpers"
1414
"github.com/NBISweden/sda-bpctl/internal/models"
1515
)
1616

1717
type mockClient struct {
18-
FilesToReturn []models.FileInfo
19-
Response *http.Response
18+
FilesToReturn []models.FileInfo
19+
FilesWithStatus []models.FileInfo
20+
Response *http.Response
2021
}
2122

2223
func (m *mockClient) GetUsersFilesWithPrefix() ([]models.FileInfo, error) {
@@ -51,14 +52,26 @@ func (m *mockClient) PostDatasetCreate(payload []byte) ([]byte, error) {
5152
return response, nil
5253
}
5354

55+
func (m *mockClient) GetFilesWithStatus(status string) ([]models.FileInfo, error) {
56+
return m.FilesWithStatus, nil
57+
}
58+
59+
func (m *mockClient) WaitForStatus(target int, status string, interval time.Duration, timeout time.Duration) ([]models.FileInfo, error) {
60+
return nil, nil
61+
}
62+
5463
func newMockClient(userID string, datasetFolder string) *mockClient {
5564
mock := &mockClient{
5665
FilesToReturn: []models.FileInfo{
5766
// Data is mocked so we expect 2 files to be included in the accession (file1.c4gh and file2.c4gh)
58-
{InboxPath: fmt.Sprintf("/%s/%s/file1.c4gh", userID, datasetFolder), Status: "verified"},
59-
{InboxPath: fmt.Sprintf("/%s/%s/file2.c4gh", userID, datasetFolder), Status: "verified"},
67+
{InboxPath: fmt.Sprintf("/%s/%s/file1.c4gh", userID, datasetFolder), Status: "ready"},
68+
{InboxPath: fmt.Sprintf("/%s/%s/file2.c4gh", userID, datasetFolder), Status: "ready"},
6069
{InboxPath: fmt.Sprintf("/%s/%s/file3.c4gh", userID, datasetFolder), Status: "error"},
61-
{InboxPath: fmt.Sprintf("/%s/%s/file4.c4gh", userID, "DATASET_OTHER"), Status: "verified"},
70+
{InboxPath: fmt.Sprintf("/%s/%s/file4.c4gh", userID, "DATASET_OTHER"), Status: "ready"},
71+
},
72+
FilesWithStatus: []models.FileInfo{
73+
{InboxPath: fmt.Sprintf("/%s/%s/file1.c4gh", userID, datasetFolder), Status: "ready"},
74+
{InboxPath: fmt.Sprintf("/%s/%s/file2.c4gh", userID, datasetFolder), Status: "ready"},
6275
},
6376
Response: &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewBufferString("ok"))},
6477
}
@@ -80,19 +93,19 @@ func TestAccession(t *testing.T) {
8093
t.Run("Test Accession", func(t *testing.T) {
8194

8295
accessionCmd.Flag("data-directory").Value.Set(workingDirectory)
83-
files, err := mock.GetUsersFiles()
96+
97+
files, err := mock.GetFilesWithStatus("ready")
8498
if err != nil {
85-
t.Error(err)
99+
t.Fail()
86100
}
87101

88-
paths := helpers.GetPathsForAccessionIDs(files, datasetFolder)
89-
nrPaths := len(paths)
90-
if nrPaths != expectedPaths {
91-
t.Logf("recieved %d/%d paths for accessionIDs", nrPaths, expectedPaths)
102+
nrFiles := len(files)
103+
if nrFiles != expectedPaths {
104+
t.Logf("recieved %d/%d paths for accessionIDs", nrFiles, expectedPaths)
92105
t.Fail()
93106
}
94107

95-
accessionIDs, err := postAccessionIDs(mock, paths, userID)
108+
accessionIDs, err := postAccessionIDs(mock, files, userID)
96109
nrAccessionIDs := len(accessionIDs)
97110
if nrAccessionIDs != expectedPaths {
98111
t.Logf("recieved %d/%d accessionIDs", nrAccessionIDs, expectedPaths)

internal/client/client.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -178,39 +178,42 @@ func (c *Client) doRequest(method, path string, body []byte) ([]byte, error) {
178178
return responseBody, nil
179179
}
180180

181-
func (c *Client) WaitForAccession(target int, interval time.Duration, timeout time.Duration) ([]string, error) {
181+
func (c *Client) WaitForStatus(target int, status string, interval time.Duration, timeout time.Duration) ([]models.FileInfo, error) {
182182
deadline := time.Now().Add(timeout)
183183
for {
184-
paths, err := c.getVerifiedFilePaths()
184+
185+
filteredFiles, err := c.GetFilesWithStatus(status)
185186
if err != nil {
186187
return nil, err
187188
}
188189

189-
if len(paths) >= target {
190-
return paths, nil
190+
current := len(filteredFiles)
191+
192+
if current >= target {
193+
return filteredFiles, nil
191194
}
192195

193196
if time.Now().After(deadline) {
194-
return nil, fmt.Errorf("timeout reached, only got %d/%d files", len(paths), target)
197+
return nil, fmt.Errorf("timeout reached, only got %d/%d files", current, target)
195198
}
196-
slog.Info(fmt.Sprintf("found %d/%d files - waiting: %s timeout: %s", len(paths), target, interval, timeout))
199+
slog.Info(fmt.Sprintf("found %d/%d files - waiting: %s timeout: %s", current, target, interval, timeout))
197200
time.Sleep(interval)
198201
}
199202
}
200203

201-
func (c *Client) getVerifiedFilePaths() ([]string, error) {
202-
files, err := c.GetUsersFilesWithPrefix()
204+
func (c *Client) GetFilesWithStatus(status string) ([]models.FileInfo, error) {
205+
allFiles, err := c.GetUsersFilesWithPrefix()
203206
if err != nil {
204207
return nil, err
205208
}
206209

207-
var paths []string
208-
for _, f := range files {
209-
if f.Status == "verified" &&
210+
var filteredFiles []models.FileInfo
211+
for _, f := range allFiles {
212+
if f.Status == status &&
210213
strings.Contains(f.InboxPath, c.datasetFolder) &&
211214
!strings.Contains(f.InboxPath, "PRIVATE") {
212-
paths = append(paths, f.InboxPath)
215+
filteredFiles = append(filteredFiles, f)
213216
}
214217
}
215-
return paths, nil
218+
return filteredFiles, nil
216219
}

internal/client/client_interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package client
22

33
import (
44
"github.com/NBISweden/sda-bpctl/internal/models"
5+
"time"
56
)
67

78
type APIClient interface {
@@ -10,4 +11,6 @@ type APIClient interface {
1011
PostFileIngest([]byte) ([]byte, error)
1112
PostFileAccession(payload []byte) ([]byte, error)
1213
PostDatasetCreate(payload []byte) ([]byte, error)
14+
GetFilesWithStatus(status string) ([]models.FileInfo, error)
15+
WaitForStatus(target int, status string, interval time.Duration, timeout time.Duration) ([]models.FileInfo, error)
1316
}

internal/config/config.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ func bindKeys(v *viper.Viper) {
9595
func setDefaults(v *viper.Viper) {
9696
v.SetDefault("JOB_TIMEOUT", 4320)
9797
v.SetDefault("JOB_POLL_RATE", 180)
98-
v.SetDefault("JOB_EXPECTED_NR_FILES", 0)
9998
v.SetDefault("JOB_DATA_DIRECTORY", "/data")
10099

101100
v.SetDefault("CLIENT_API_HOST", "https://api.bp.nbis.se")

internal/dataset/dataset.go

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dataset
22

33
import (
4-
"bufio"
54
"encoding/json"
65
"errors"
76
"fmt"
@@ -57,7 +56,7 @@ var datasetCmd = &cobra.Command{
5756
}
5857
}
5958

60-
fileIDsList, err := getFileIDs(datasetFolder, api)
59+
fileIDsList, err := api.GetFilesWithStatus("verified")
6160
if err != nil {
6261
return err
6362
}
@@ -95,10 +94,9 @@ type UserFiles struct {
9594
InboxPath string `json:"inboxPath"`
9695
}
9796

98-
func Run(api *client.Client, datasetFolder string, datasetID string, userID string, fileIDsList []string) error {
97+
func Run(api *client.Client, datasetFolder string, datasetID string, userID string) error {
9998

100-
// TODO: Optimize this; another query to GetUsersFilesWithPrefix is redundant since It will hold the same information as in the fileIDsList []string
101-
files, err := api.GetUsersFilesWithPrefix()
99+
files, err := api.GetFilesWithStatus("ready")
102100
if err != nil {
103101
return err
104102
}
@@ -108,51 +106,33 @@ func Run(api *client.Client, datasetFolder string, datasetID string, userID stri
108106
return err
109107
}
110108

111-
err = createDataset(api, datasetID, userID, fileIDsList)
109+
err = createDataset(api, datasetID, userID, files)
112110
if err != nil {
113111
return err
114112
}
115113
return nil
116114
}
117115

118-
func getFileIDs(datasetFolder string, api client.APIClient) ([]string, error) {
119-
var fileIDsList []string
120-
filePath := helpers.GetFileIDsPath(DataDirectory, datasetFolder)
121-
if _, err := os.Stat(filePath); errors.Is(err, os.ErrNotExist) {
122-
files, err := api.GetUsersFilesWithPrefix()
123-
if err != nil {
124-
return nil, err
125-
}
126-
fileIDsList = helpers.GetPathsForAccessionIDs(files, datasetFolder)
127-
return fileIDsList, nil
128-
}
129-
file, err := os.Open(filePath)
130-
if err != nil {
131-
return nil, err
116+
func createDataset(api client.APIClient, datasetID string, userID string, files []models.FileInfo) error {
117+
var accessionIDs []string
118+
for _, file := range files {
119+
accessionIDs = append(accessionIDs, file.AccessionID)
132120
}
133-
defer file.Close() //nolint:errcheck
134121

135-
slog.Info("reading", "filePath", filePath)
136-
scanner := bufio.NewScanner(file)
137-
for scanner.Scan() {
138-
fileIDsList = append(fileIDsList, scanner.Text())
139-
}
140-
return fileIDsList, nil
141-
}
122+
nrFiles := len(accessionIDs)
142123

143-
func createDataset(api client.APIClient, datasetID string, userID string, fileIDsList []string) error {
144-
slog.Info("starting dataset")
124+
slog.Info("starting dataset", "nr_files", nrFiles)
145125

146-
if len(fileIDsList) > 100 {
147-
err := sendInChunks(fileIDsList, api, datasetID, userID)
126+
if nrFiles > 100 {
127+
err := sendInChunks(accessionIDs, api, datasetID, userID)
148128
if err != nil {
149129
return err
150130
}
151131
}
152132

153-
if len(fileIDsList) <= 100 {
133+
if len(files) <= 100 {
154134
payload := Payload{
155-
AccessionIDs: fileIDsList,
135+
AccessionIDs: accessionIDs,
156136
DatasetID: datasetID,
157137
User: userID,
158138
}

0 commit comments

Comments
 (0)