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

concurrency_test.go « rubyserver « gitaly « internal - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 686269a18ce3699bc26a6e6c231e36b74feebc40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package rubyserver

import (
	"fmt"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/gitaly/internal/gitaly/config"
	"gitlab.com/gitlab-org/gitaly/internal/testhelper"
	"google.golang.org/grpc/codes"
	healthpb "google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/status"
)

func waitPing(s *Server) error {
	var err error
	for start := time.Now(); time.Since(start) < ConnectTimeout; time.Sleep(100 * time.Millisecond) {
		err = makeRequest(s)
		if err == nil {
			return nil
		}
	}
	return err
}

// This benchmark lets you see what happens when you throw a lot of
// concurrent traffic at gitaly-ruby.
func BenchmarkConcurrency(b *testing.B) {
	config.Config.Ruby.NumWorkers = 2

	s := New(config.Config)
	require.NoError(b, s.Start())
	defer s.Stop()

	// Warm-up: wait for gitaly-ruby to boot
	if err := waitPing(s); err != nil {
		b.Fatal(err)
	}

	concurrency := 100
	b.Run(fmt.Sprintf("concurrency %d", concurrency), func(b *testing.B) {
		errCh := make(chan error)
		errCount := make(chan int)
		go func() {
			count := 0
			for err := range errCh {
				b.Log(err)
				count++
			}
			errCount <- count
		}()

		wg := &sync.WaitGroup{}
		for i := 0; i < concurrency; i++ {
			wg.Add(1)
			go func() {
				defer wg.Done()

				for j := 0; j < 1000; j++ {
					err := makeRequest(s)
					if err != nil {
						errCh <- err
					}

					switch status.Code(err) {
					case codes.Unavailable:
						return
					case codes.DeadlineExceeded:
						return
					}
				}
			}()
		}

		wg.Wait()
		close(errCh)

		if count := <-errCount; count != 0 {
			b.Fatalf("received %d errors", count)
		}
	})
}

func makeRequest(s *Server) error {
	ctx, cancel := testhelper.Context(testhelper.ContextWithTimeout(time.Second))
	defer cancel()

	conn, err := s.getConnection(ctx)
	if err != nil {
		return err
	}

	client := healthpb.NewHealthClient(conn)
	_, err = client.Check(ctx, &healthpb.HealthCheckRequest{})
	return err
}