@@ -28,11 +28,14 @@ import (
28
28
// on disk and we haven't written Atlantis (yet) to handle concurrent execution
29
29
// within this workspace.
30
30
type WorkingDirLocker interface {
31
- // TryLock tries to acquire a lock for this repo, pull, workspace, and path.
31
+ // TryLockWithRetry tries to acquire a lock for this repo, pull, workspace, and path.
32
32
// It returns a function that should be used to unlock the workspace and
33
33
// an error if the workspace is already locked. The error is expected to
34
34
// be printed to the pull request.
35
- TryLock (repoFullName string , pullNum int , workspace string , path string ) (func (), error )
35
+ // The caller can define if the function should automatically retry to acquire the lock
36
+ // if either the pull request or the workspace is locked already.
37
+ TryLockWithRetry (repoFullName string , pullNum int , workspace string , path string , retryWorkspaceLocked bool , retryPullLocked bool ) (func (), error )
38
+
36
39
// TryLockPull tries to acquire a lock for all the workspaces in this repo
37
40
// and pull.
38
41
// It returns a function that should be used to unlock the workspace and
@@ -56,8 +59,8 @@ type DefaultWorkingDirLocker struct {
56
59
57
60
// NewDefaultWorkingDirLocker is a constructor.
58
61
func NewDefaultWorkingDirLocker (lockAcquireTimeoutSeconds int ) * DefaultWorkingDirLocker {
59
- if lockAcquireTimeoutSeconds < 1 {
60
- lockAcquireTimeoutSeconds = 1
62
+ if lockAcquireTimeoutSeconds < 0 {
63
+ lockAcquireTimeoutSeconds = 0
61
64
}
62
65
63
66
return & DefaultWorkingDirLocker {
@@ -83,7 +86,7 @@ func (d *DefaultWorkingDirLocker) TryLockPull(repoFullName string, pullNum int)
83
86
}, nil
84
87
}
85
88
86
- func (d * DefaultWorkingDirLocker ) TryLock (repoFullName string , pullNum int , workspace string , path string ) (func (), error ) {
89
+ func (d * DefaultWorkingDirLocker ) TryLockWithRetry (repoFullName string , pullNum int , workspace string , path string , retryWorkspaceLocked bool , retryPullLocked bool ) (func (), error ) {
87
90
ticker := time .NewTicker (500 * time .Millisecond )
88
91
timeout := time .NewTimer (time .Duration (d .lockAcquireTimeoutSeconds ) * time .Second )
89
92
@@ -97,8 +100,21 @@ func (d *DefaultWorkingDirLocker) TryLock(repoFullName string, pullNum int, work
97
100
" command that is running for this pull request.\n " +
98
101
"Wait until the previous command is complete and try again" , workspace , path )
99
102
case <- ticker .C :
100
- lockAcquired := d .tryAcquireLock (pullKey , workspaceKey )
101
- if lockAcquired {
103
+ pullInUse , workspaceInUse := d .tryAcquireLock (pullKey , workspaceKey )
104
+
105
+ if pullInUse && ! retryPullLocked {
106
+ return func () {}, fmt .Errorf ("the %s workspace at path %s is currently locked by another" +
107
+ " command that is running for this pull request.\n " +
108
+ "Wait until the previous command is complete and try again" , workspace , path )
109
+ }
110
+
111
+ if workspaceInUse && ! retryWorkspaceLocked {
112
+ return func () {}, fmt .Errorf ("the %s workspace at path %s is currently locked by another" +
113
+ " command that is running for this pull request.\n " +
114
+ "Wait until the previous command is complete and try again" , workspace , path )
115
+ }
116
+
117
+ if ! workspaceInUse && ! pullInUse {
102
118
return func () {
103
119
d .unlock (repoFullName , pullNum , workspace , path )
104
120
}, nil
@@ -107,22 +123,27 @@ func (d *DefaultWorkingDirLocker) TryLock(repoFullName string, pullNum int, work
107
123
}
108
124
}
109
125
110
- func (d * DefaultWorkingDirLocker ) tryAcquireLock (pullKey string , workspaceKey string ) bool {
126
+ func (d * DefaultWorkingDirLocker ) tryAcquireLock (pullKey string , workspaceKey string ) ( bool , bool ) {
111
127
d .mutex .Lock ()
112
128
defer d .mutex .Unlock ()
113
129
114
- acquireLock := true
130
+ pullInUse := false
131
+ workspaceInUse := false
115
132
for _ , l := range d .locks {
116
- if l == pullKey || l == workspaceKey {
117
- acquireLock = false
133
+ if l == pullKey {
134
+ pullInUse = true
135
+ }
136
+
137
+ if l == workspaceKey {
138
+ workspaceInUse = true
118
139
}
119
140
}
120
141
121
- if acquireLock {
142
+ if ! pullInUse && ! workspaceInUse {
122
143
d .locks = append (d .locks , workspaceKey )
123
144
}
124
145
125
- return acquireLock
146
+ return pullInUse , workspaceInUse
126
147
}
127
148
128
149
// Unlock unlocks the workspace for this pull.
0 commit comments