Skip to content

Commit 6a77e84

Browse files
authored
refactor(api,ui): run retention policy with feature flipping (#5755)
Signed-off-by: richardlt <[email protected]>
1 parent c4472b8 commit 6a77e84

File tree

11 files changed

+268
-87
lines changed

11 files changed

+268
-87
lines changed

docs/content/docs/concepts/workflow/retention.md

+51-15
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,62 @@ title: "Retention"
33
weight: 10
44
---
55

6-
You can configure the workflow run retention in the workflow advanced section on the CDS UI.
6+
You can configure two options in Workflow advanced section on the CDS UI:
7+
* Workflow run retention policy. A lua rule to check if a run should be kept or not.
8+
* Maximum number of Workflow Runs. The maximum number of run to keep for the Workflow.
79

810
![retention.png](../images/workflow_retention.png)
911

12+
The dry run button allows you to test your lua expression. The result is a table filled with all runs that would be kept
1013

11-
* The first line defines the number maximum of runs that CDS can keep for this workflow. Only a CDS administrator can update this value.
14+
## Workflow run retention policy
1215

13-
* On the second line, you will be able to define your retention policy through a lua condition.
14-
You will be able to use these variables:
15-
* <b>run_days_before</b>: to identify runs older than x days
16-
* <b>git_branch_exist</b>: to identify if the git branch used for this run still exists on the git repository
17-
* <b>run_status</b>: to identidy run status
18-
* <b>gerrit_change_merged</b>: to identify if the gerrit change has been merged
19-
* <b>gerrit_change_abandoned</b>: to identify if the gerrit change has been abandoned
20-
* <b>gerrit_change_days_before</b>: to identify gerrit change older than x days
21-
* and all variables defined in your workflow payload
16+
{{% notice note %}}
17+
This feature is not currently enabled by default. However, you can try this feature on a CDS project using the feature flipping.
18+
To activate the feature you can create a file like the following:
19+
```sh
20+
cat <<EOF > workflow-retention-policy.yml
21+
name: workflow-retention-policy
22+
rule: return project_key == "KEY_FOR_PROJECT_THAT_YOU_WANT_TO_ACTIVATE"
23+
EOF
24+
cdsctl admin feature import workflow-retention-policy.yml
25+
```
26+
{{% /notice %}}
2227

23-
For example, the rule defined above means:
28+
Retention policy is defined through a lua condition. This condition should be evaluated as **true** to keep a Workflow Run.
2429

25-
Keep workflow run for 365 days, but if branch does not exist on repository, only keep the run for 2 days.
26-
30+
You will be able to use these variables in conditions:
31+
* **run_days_before** (number): count of days between Workflow creation date and now.
32+
* **git_branch_exist** (string: true|false): True if a *git.branch* variable is set and branch still exists on the git repository.
33+
* **run_status** (string: Success|Fail|...): the Workflow Run status.
34+
* **gerrit_change_merged** (string: true|false): to identify if the gerrit change has been merged.
35+
* **gerrit_change_abandoned** (string: true|false): to identify if the gerrit change has been abandoned.
36+
* **gerrit_change_days_before** (number): to identify gerrit change older than x days.
37+
* All other variables from the Workflow Run payload (ex: cds_triggered_by_username, git_branch...).
2738

28-
* The dry run button allows you to test your lua expression. The result is a table filled with all runs that would be kept
39+
Examples:
40+
```lua
41+
-- Keep Run for 365 days
42+
return run_days_before < 365
43+
````
44+
```lua
45+
-- Keep Run for ever
46+
return true
47+
```
48+
49+
## Maximum number of Workflow Runs
50+
51+
{{% notice note %}}
52+
This feature is not currently enabled by default. However, you can try this feature on a CDS project using the feature flipping.
53+
To activate the feature you can create a file like the following:
54+
```sh
55+
cat <<EOF > workflow-retention-maxruns.yml
56+
name: workflow-retention-maxruns
57+
rule: return project_key == "KEY_FOR_PROJECT_THAT_YOU_WANT_TO_ACTIVATE"
58+
EOF
59+
cdsctl admin feature import workflow-retention-maxruns.yml
60+
```
61+
{{% /notice %}}
62+
63+
This value can be set only by a CDS administrator. In some case it prevent a Workflow to keep a lot of runs.
64+
When this feature is active, you'll not be able to start new Runs on a Workflow if the maximum count was reached.

engine/api/purge/purge.go

+42
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import (
1010
"github.com/rockbears/log"
1111
"go.opencensus.io/stats"
1212

13+
"github.com/ovh/cds/engine/api/database/gorpmapping"
1314
"github.com/ovh/cds/engine/api/integration"
1415
"github.com/ovh/cds/engine/api/objectstore"
1516
"github.com/ovh/cds/engine/api/project"
1617
"github.com/ovh/cds/engine/api/services"
1718
"github.com/ovh/cds/engine/api/workflow"
1819
"github.com/ovh/cds/engine/cache"
20+
"github.com/ovh/cds/engine/featureflipping"
1921
"github.com/ovh/cds/sdk"
2022
"github.com/ovh/cds/sdk/telemetry"
2123
)
@@ -55,6 +57,11 @@ func WorkflowRuns(ctx context.Context, DBFunc func() *gorp.DbMap, sharedStorage
5557
return
5658
}
5759
case <-tickPurge.C:
60+
// Check all workflows to mark runs that should be deleted
61+
if err := MarkWorkflowRuns(ctx, DBFunc(), workflowRunsMarkToDelete); err != nil {
62+
log.Warn(ctx, "purge> Error: %v", err)
63+
}
64+
5865
log.Debug(ctx, "purge> Deleting all workflow run marked to delete...")
5966
if err := deleteWorkflowRunsHistory(ctx, DBFunc(), sharedStorage, workflowRunsDeleted); err != nil {
6067
log.Warn(ctx, "purge> Error on deleteWorkflowRunsHistory : %v", err)
@@ -84,6 +91,41 @@ func Workflow(ctx context.Context, store cache.Store, DBFunc func() *gorp.DbMap,
8491
}
8592
}
8693

94+
// MarkWorkflowRuns Deprecated: old method to mark runs to delete
95+
func MarkWorkflowRuns(ctx context.Context, db *gorp.DbMap, workflowRunsMarkToDelete *stats.Int64Measure) error {
96+
dao := new(workflow.WorkflowDAO)
97+
dao.Filters.DisableFilterDeletedWorkflow = false
98+
wfs, err := dao.LoadAll(ctx, db)
99+
if err != nil {
100+
return err
101+
}
102+
for _, wf := range wfs {
103+
_, enabled := featureflipping.IsEnabled(ctx, gorpmapping.Mapper, db, sdk.FeaturePurgeName, map[string]string{"project_key": wf.ProjectKey})
104+
if enabled {
105+
continue
106+
}
107+
tx, err := db.Begin()
108+
if err != nil {
109+
log.Error(ctx, "workflow.PurgeWorkflowRuns> error %v", err)
110+
tx.Rollback() // nolint
111+
continue
112+
}
113+
if err := workflow.PurgeWorkflowRun(ctx, tx, wf); err != nil {
114+
log.Error(ctx, "workflow.PurgeWorkflowRuns> error %v", err)
115+
tx.Rollback() // nolint
116+
continue
117+
}
118+
if err := tx.Commit(); err != nil {
119+
log.Error(ctx, "workflow.PurgeWorkflowRuns> unable to commit transaction: %v", err)
120+
_ = tx.Rollback()
121+
continue
122+
}
123+
}
124+
125+
workflow.CountWorkflowRunsMarkToDelete(ctx, db, workflowRunsMarkToDelete)
126+
return nil
127+
}
128+
87129
// workflows purges all marked workflows
88130
func workflows(ctx context.Context, db *gorp.DbMap, store cache.Store, workflowRunsMarkToDelete *stats.Int64Measure) error {
89131
query := "SELECT id, project_id FROM workflow WHERE to_delete = true ORDER BY id ASC"

engine/api/purge/purge_run.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import (
1111
"github.com/rockbears/log"
1212
"go.opencensus.io/stats"
1313

14+
"github.com/ovh/cds/engine/api/database/gorpmapping"
1415
"github.com/ovh/cds/engine/api/event"
1516
"github.com/ovh/cds/engine/api/repositoriesmanager"
1617
"github.com/ovh/cds/engine/api/workflow"
1718
"github.com/ovh/cds/engine/cache"
19+
"github.com/ovh/cds/engine/featureflipping"
1820
"github.com/ovh/cds/sdk"
1921
"github.com/ovh/cds/sdk/luascript"
2022
)
@@ -33,7 +35,7 @@ const (
3335
RunChangeDayBefore = "gerrit_change_days_before"
3436
)
3537

36-
func GetRetetionPolicyVariables() []string {
38+
func GetRetentionPolicyVariables() []string {
3739
return []string{RunDaysBefore, RunStatus, RunGitBranchExist, RunChangeMerged, RunChangeAbandoned, RunChangeDayBefore, RunChangeExist}
3840
}
3941

@@ -44,6 +46,10 @@ func markWorkflowRunsToDelete(ctx context.Context, store cache.Store, db *gorp.D
4446
return err
4547
}
4648
for _, wf := range wfs {
49+
_, enabled := featureflipping.IsEnabled(ctx, gorpmapping.Mapper, db, sdk.FeaturePurgeName, map[string]string{"project_key": wf.ProjectKey})
50+
if !enabled {
51+
continue
52+
}
4753
if err := ApplyRetentionPolicyOnWorkflow(ctx, store, db, wf, MarkAsDeleteOptions{DryRun: false}, nil); err != nil {
4854
ctx = sdk.ContextWithStacktrace(ctx, err)
4955
log.Error(ctx, "%v", err)

engine/api/workflow.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func (api *API) getRetentionPolicySuggestionHandler() service.Handler {
155155
}
156156
}
157157

158-
retentionPolicySuggestion := purge.GetRetetionPolicyVariables()
158+
retentionPolicySuggestion := purge.GetRetentionPolicyVariables()
159159
for k := range varsPayload {
160160
retentionPolicySuggestion = append(retentionPolicySuggestion, k)
161161
}

engine/api/workflow_run.go

+22
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,28 @@ func (api *API) initWorkflowRun(ctx context.Context, projKey string, wf *sdk.Wor
11041104
}
11051105
workflow.ResyncNodeRunsWithCommits(ctx, api.mustDB(), api.Cache, *p, report)
11061106

1107+
_, enabled := featureflipping.IsEnabled(ctx, gorpmapping.Mapper, api.mustDB(), sdk.FeaturePurgeName, map[string]string{"project_key": wf.ProjectKey})
1108+
if !enabled {
1109+
// Purge workflow run
1110+
api.GoRoutines.Exec(ctx, "workflow.PurgeWorkflowRun", func(ctx context.Context) {
1111+
tx, err := api.mustDB().Begin()
1112+
defer tx.Rollback() // nolint
1113+
if err != nil {
1114+
log.Error(ctx, "workflow.PurgeWorkflowRun> error %v", err)
1115+
return
1116+
}
1117+
if err := workflow.PurgeWorkflowRun(ctx, tx, *wf); err != nil {
1118+
log.Error(ctx, "workflow.PurgeWorkflowRun> error %v", err)
1119+
return
1120+
}
1121+
if err := tx.Commit(); err != nil {
1122+
log.Error(ctx, "workflow.PurgeWorkflowRun> unable to commit transaction: %v", err)
1123+
return
1124+
}
1125+
workflow.CountWorkflowRunsMarkToDelete(ctx, api.mustDB(), api.Metrics.WorkflowRunsMarkToDelete)
1126+
})
1127+
}
1128+
11071129
// Update parent
11081130
for i := range report.WorkflowRuns() {
11091131
run := &report.WorkflowRuns()[i]

sdk/featureflipping.go

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const (
66
FeatureCDNArtifact FeatureName = "cdn-artifact"
77
FeatureCDNJobLogs FeatureName = "cdn-job-logs"
88
FeatureMFARequired FeatureName = "mfa_required"
9+
FeaturePurgeName FeatureName = "workflow-retention-policy"
910
FeaturePurgeMaxRuns FeatureName = "workflow-retention-maxruns"
1011
FeatureTracing FeatureName = "tracing"
1112
)

ui/src/app/service/feature/feature.service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Observable } from 'rxjs';
66
export enum FeatureNames {
77
CDNJobLogs = 'cdn-job-logs',
88
CDNArtifact = 'cdn-artifact',
9+
WorkflowRetentionPolicy = 'workflow-retention-policy',
910
WorkflowRetentionMaxRuns = 'workflow-retention-maxruns'
1011
}
1112

0 commit comments

Comments
 (0)