Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2020-10-13 09:16:21 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2020-10-16 10:18:37 +0300
commit902e3bf932344c39bf089e5c6145e493bdcee2cf (patch)
tree094ebb68801470943f814064ee806087b79bde99
parente07f2ddf3ab854b0edadee065ec5c881a4e9fce7 (diff)
hook: Stop transactions on pre-receive hook failure
The pre-receive hook business logic is only executed on primary nodes in order to avoid executing custom hooks and the likes multiple times. Failures of the pre-receive hook e.g. because of a denied access will thus only ever be detected on primaries. While correct, this has unfortunate side effects when transactions come into play. As the primary will not vote on such a transaction, secondaries will wait for quorum and eventually time out as the primary is never going to cast its own vote. While the end result is the same as the transaction has failed, it will raise a misleading error message and cause a delay of 10 seconds. With our newly grown ability to stop transactions, we can now do better: in case the pre-receive hook declines the push, we can now gracefully stop the transaction. As a result, secondaries will know to abort and not make a big fuzz about it.
-rw-r--r--internal/gitaly/hook/prereceive.go3
-rw-r--r--internal/gitaly/hook/transactions.go20
2 files changed, 22 insertions, 1 deletions
diff --git a/internal/gitaly/hook/prereceive.go b/internal/gitaly/hook/prereceive.go
index 8f8fa79cf..2754b572d 100644
--- a/internal/gitaly/hook/prereceive.go
+++ b/internal/gitaly/hook/prereceive.go
@@ -53,6 +53,9 @@ func (m *GitLabHookManager) PreReceiveHook(ctx context.Context, repo *gitalypb.R
// Only the primary should execute hooks and increment reference counters.
if primary {
if err := m.preReceiveHook(ctx, repo, env, changes, stdout, stderr); err != nil {
+ // If the pre-receive hook declines the push, then we need to stop any
+ // secondaries voting on the transaction.
+ m.stopTransaction(ctx, env)
return err
}
}
diff --git a/internal/gitaly/hook/transactions.go b/internal/gitaly/hook/transactions.go
index 34b6b758c..6d52ebf9d 100644
--- a/internal/gitaly/hook/transactions.go
+++ b/internal/gitaly/hook/transactions.go
@@ -87,8 +87,26 @@ func (m *GitLabHookManager) voteOnTransaction(ctx context.Context, hash []byte,
return err
}
- if response.State != gitalypb.VoteTransactionResponse_COMMIT {
+ switch response.State {
+ case gitalypb.VoteTransactionResponse_COMMIT:
+ return nil
+ case gitalypb.VoteTransactionResponse_ABORT:
return errors.New("transaction was aborted")
+ case gitalypb.VoteTransactionResponse_STOP:
+ return errors.New("transaction was stopped")
+ default:
+ return errors.New("invalid transaction state")
+ }
+ })
+}
+
+func (m *GitLabHookManager) stopTransaction(ctx context.Context, env []string) error {
+ return m.runWithTransaction(ctx, env, func(ctx context.Context, tx metadata.Transaction, client gitalypb.RefTransactionClient) error {
+ _, err := client.StopTransaction(ctx, &gitalypb.StopTransactionRequest{
+ TransactionId: tx.ID,
+ })
+ if err != nil {
+ return err
}
return nil