File: fork_reconnect_stress_spec.rb

package info (click to toggle)
ruby-mongo 2.21.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 14,764 kB
  • sloc: ruby: 108,806; makefile: 5; sh: 2
file content (108 lines) | stat: -rw-r--r-- 3,200 bytes parent folder | download
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
99
100
101
102
103
104
105
106
107
108
# frozen_string_literal: true
# rubocop:todo all

require 'spec_helper'

describe 'fork reconnect' do
  require_fork
  require_mri

  # On multi-shard sharded clusters a succeeding write request does not
  # guarantee that the next operation will succeed (since it could be sent to
  # another shard with a dead connection).
  require_no_multi_mongos

  require_stress

  let(:client) { authorized_client }

  describe 'client' do
    it 'works after fork' do
      # Perform a write so that we discover the current primary.
      # Previous test may have stepped down the server that authorized client
      # considers the primary.
      # In standalone deployments there are no retries, hence execute the
      # operation twice manually.
      client['foo'].insert_one(test: 1) rescue nil
      client['foo'].insert_one(test: 1)

      pids = []
      deadline = Mongo::Utils.monotonic_time + 5
      1.upto(10) do
        if pid = fork
          pids << pid
        else
          Utils.wrap_forked_child do
            while Mongo::Utils.monotonic_time < deadline
              client.database.command(hello: 1).should be_a(Mongo::Operation::Result)
            end
          end
        end
      end

      while Mongo::Utils.monotonic_time < deadline
        # Use a read which is retried in case of an error
        client['foo'].find(test: 1).to_a
      end

      pids.each do |pid|
        pid, status = Process.wait2(pid)
        status.exitstatus.should == 0
      end
    end

    retry_test
    context 'when parent is operating on client during the fork' do
      # This test intermittently fails in evergreen with pool size of 5,
      # with a number of pending connections in the pool.
      # The reason could be that handshaking is slow or operations are slow
      # post handshakes.
      # Sometimes it seems the monitoring connection experiences network
      # errors (despite being a loopback connection) which causes the test
      # to fail as then server selection fails.
      # The retry_test is to deal with network errors on monitoring connection.

      let(:client) { authorized_client.with(max_pool_size: 10,
        wait_queue_timeout: 10, socket_timeout: 2, connect_timeout: 2) }

      it 'works' do
        client.database.command(hello: 1).should be_a(Mongo::Operation::Result)

        threads = []
        5.times do
          threads << Thread.new do
            loop do
              client['foo'].find(test: 1).to_a
            end
          end
        end

        pids = []
        deadline = Mongo::Utils.monotonic_time + 5
        10.times do
          if pid = fork
            pids << pid
          else
            Utils.wrap_forked_child do
              while Mongo::Utils.monotonic_time < deadline
                client.database.command(hello: 1).should be_a(Mongo::Operation::Result)
              end
            end
          end
        end

        while Mongo::Utils.monotonic_time < deadline
          sleep 0.1
        end

        threads.map(&:kill)
        threads.map(&:join)

        pids.each do |pid|
          pid, status = Process.wait2(pid)
          status.exitstatus.should == 0
        end
      end
    end
  end
end