Skip to content

Commit b4d8a17

Browse files
Merge branch 'master' into csot
2 parents 03b3613 + 3c5dc93 commit b4d8a17

File tree

6 files changed

+140
-111
lines changed

6 files changed

+140
-111
lines changed

.github/workflows/cleanup.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: "Dry-Run Cleanup"
2+
run-name: "Dry Run Cleanup for ${{ github.ref }}"
3+
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
confirm:
8+
description: Indicate whether you want this workflow to run (must be "true")
9+
required: true
10+
type: string
11+
tag:
12+
description: The name of the tag (and release) to clean up
13+
required: true
14+
type: string
15+
16+
jobs:
17+
release:
18+
name: "Dry-Run Cleanup"
19+
environment: release
20+
runs-on: 'ubuntu-latest'
21+
if: ${{ inputs.confirm == 'true' }}
22+
23+
permissions:
24+
# required for all workflows
25+
security-events: write
26+
27+
# required to fetch internal or private CodeQL packs
28+
packages: read
29+
30+
# only required for workflows in private repositories
31+
actions: read
32+
contents: write
33+
34+
# required by the mongodb-labs/drivers-github-tools/setup@v2 step
35+
# also required by `rubygems/release-gem`
36+
id-token: write
37+
38+
steps:
39+
- name: "Run the cleanup action"
40+
uses: mongodb-labs/drivers-github-tools/ruby/cleanup@v2
41+
with:
42+
app_id: ${{ vars.APP_ID }}
43+
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
44+
tag: ${{ inputs.tag }}

.github/workflows/release.yml

Lines changed: 20 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
name: "Driver Release"
2-
run-name: "Ruby Driver Release ${{ github.ref_name }}"
2+
run-name: "Driver Release for ${{ github.ref }}"
33

4-
on: workflow_dispatch
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
dry_run:
8+
description: Whether this is a dry run or not
9+
required: true
10+
default: true
11+
type: boolean
512

613
env:
14+
SILK_ASSET_GROUP: mongodb-ruby-driver
715
RELEASE_MESSAGE_TEMPLATE: |
816
Version {0} of the [MongoDB Ruby Driver](https://rubygems.org/gems/mongo) is now available.
917
@@ -43,88 +51,17 @@ jobs:
4351
id-token: write
4452

4553
steps:
46-
- name: "Create temporary app token"
47-
uses: actions/create-github-app-token@v1
48-
id: app-token
49-
with:
50-
app-id: ${{ vars.APP_ID }}
51-
private-key: ${{ secrets.APP_PRIVATE_KEY }}
52-
53-
- name: "Store GitHub token in environment"
54-
run: echo "GH_TOKEN=${{ steps.app-token.outputs.token }}" >> "$GITHUB_ENV"
55-
shell: bash
56-
57-
- name: Checkout repository
58-
uses: actions/checkout@v4
59-
with:
60-
token: ${{ env.GH_TOKEN }}
61-
62-
- name: Setup Ruby
63-
uses: ruby/setup-ruby@v1
64-
with:
65-
ruby-version: '3.2'
66-
bundler-cache: true
67-
68-
- name: Setup GitHub tooling for DBX Drivers
69-
uses: mongodb-labs/drivers-github-tools/setup@v2
54+
- name: "Run the publish action"
55+
uses: mongodb-labs/drivers-github-tools/ruby/publish@v2
7056
with:
57+
app_id: ${{ vars.APP_ID }}
58+
app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
7159
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
7260
aws_region_name: ${{ vars.AWS_REGION_NAME }}
7361
aws_secret_id: ${{ secrets.AWS_SECRET_ID }}
74-
75-
- name: Get the driver version
76-
shell: bash
77-
run: |
78-
echo "DRIVER_VERSION=$(ruby -Ilib -rmongo/version -e 'puts Mongo::VERSION')" >> "$GITHUB_ENV"
79-
80-
- name: Set output gem file name
81-
shell: bash
82-
run: |
83-
echo "GEM_FILE_NAME=mongo-${{ env.DRIVER_VERSION }}.gem" >> "$GITHUB_ENV"
84-
85-
- name: Build the gem
86-
shell: bash
87-
run: |
88-
gem build --output=${{ env.GEM_FILE_NAME }} mongo.gemspec
89-
90-
- name: Sign the gem
91-
uses: mongodb-labs/drivers-github-tools/gpg-sign@v2
92-
with:
93-
filenames: '${{ env.GEM_FILE_NAME }}'
94-
95-
- name: Create and sign the tag
96-
uses: mongodb-labs/drivers-github-tools/git-sign@v2
97-
with:
98-
command: "git tag -u ${{ env.GPG_KEY_ID }} -m 'Release tag for v${{ env.DRIVER_VERSION }}' v${{ env.DRIVER_VERSION }}"
99-
100-
- name: Push the tag to the repository
101-
shell: bash
102-
run: |
103-
git push origin v${{ env.DRIVER_VERSION }}
104-
105-
- name: Create a new release
106-
shell: bash
107-
run: gh release create v${{ env.DRIVER_VERSION }} --title ${{ env.DRIVER_VERSION }} --generate-notes --draft
108-
109-
- name: Capture the changelog
110-
shell: bash
111-
run: gh release view v${{ env.DRIVER_VERSION }} --json body --template '{{ .body }}' >> changelog
112-
113-
- name: Prepare release message
114-
shell: bash
115-
run: |
116-
echo "${{ format(env.RELEASE_MESSAGE_TEMPLATE, env.DRIVER_VERSION) }}" > release-message
117-
cat changelog >> release-message
118-
119-
- name: Update release information
120-
shell: bash
121-
run: |
122-
echo "RELEASE_URL=$(gh release edit v${{ env.DRIVER_VERSION }} --notes-file release-message)" >> "$GITHUB_ENV"
123-
124-
- name: Upload release artifacts
125-
run: gh release upload v${{ env.DRIVER_VERSION }} ${{ env.GEM_FILE_NAME }} ${{ env.RELEASE_ASSETS }}/${{ env.GEM_FILE_NAME }}.sig
126-
127-
- name: Publish the gem
128-
uses: rubygems/release-gem@v1
129-
with:
130-
await-release: false
62+
dry_run: ${{ inputs.dry_run }}
63+
gem_name: mongo
64+
product_name: Ruby Driver
65+
product_id: mongodb-ruby-driver
66+
release_message_template: ${{ env.RELEASE_MESSAGE_TEMPLATE }}
67+
silk_asset_group: ${{ env.SILK_ASSET_GROUP }}

Rakefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ task :build do
4646
WARNING
4747
end
4848

49+
# `rake version` is used by the deployment system so get the release version
50+
# of the product beng deployed. It must do nothing more than just print the
51+
# product version number.
52+
#
53+
# See the mongodb-labs/driver-github-tools/ruby/publish Github action.
54+
desc "Print the current value of Mongo::VERSION"
55+
task :version do
56+
require 'mongo/version'
57+
58+
puts Mongo::VERSION
59+
end
60+
4961
# overrides the default Bundler-provided `release` task, which also
5062
# builds the gem. Our release process assumes the gem has already
5163
# been built (and signed via GPG), so we just need `rake release` to

lib/mongo/retryable/base_worker.rb

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ def initialize(retryable)
4949

5050
private
5151

52-
# Indicate which exception classes that are generally retryable.
52+
# Indicate which exception classes that are generally retryable
53+
# when using modern retries mechanism.
5354
#
5455
# @return [ Array<Mongo:Error> ] Array of exception classes that are
5556
# considered retryable.
@@ -58,18 +59,42 @@ def retryable_exceptions
5859
Error::ConnectionPerished,
5960
Error::ServerNotUsable,
6061
Error::SocketError,
61-
Error::SocketTimeoutError
62+
Error::SocketTimeoutError,
6263
].freeze
6364
end
6465

66+
# Indicate which exception classes that are generally retryable
67+
# when using legacy retries mechanism.
68+
#
69+
# @return [ Array<Mongo:Error> ] Array of exception classes that are
70+
# considered retryable.
71+
def legacy_retryable_exceptions
72+
[
73+
Error::ConnectionPerished,
74+
Error::ServerNotUsable,
75+
Error::SocketError,
76+
Error::SocketTimeoutError,
77+
Error::PoolClearedError,
78+
Error::PoolPausedError,
79+
].freeze
80+
end
81+
82+
6583
# Tests to see if the given exception instance is of a type that can
66-
# be retried.
84+
# be retried with modern retry mechanism.
6785
#
6886
# @return [ true | false ] true if the exception is retryable.
6987
def is_retryable_exception?(e)
7088
retryable_exceptions.any? { |klass| klass === e }
7189
end
7290

91+
# Tests to see if the given exception instance is of a type that can
92+
# be retried with legacy retry mechanism.
93+
#
94+
# @return [ true | false ] true if the exception is retryable.
95+
def is_legacy_retryable_exception?(e)
96+
legacy_retryable_exceptions.any? { |klass| klass === e }
97+
end
7398
# Logs the given deprecation warning the first time it is called for a
7499
# given key; after that, it does nothing when given the same key.
75100
def deprecation_warning(key, warning)

lib/mongo/retryable/read_worker.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,10 @@ def legacy_read_with_retry(session, server_selector, context = nil, &block)
227227
context&.check_timeout!
228228
attempt = attempt ? attempt + 1 : 1
229229
yield select_server(cluster, server_selector, session)
230-
rescue *retryable_exceptions, Error::OperationFailure::Family, Error::PoolError => e
230+
rescue *legacy_retryable_exceptions, Error::OperationFailure::Family => e
231231
e.add_notes('legacy retry', "attempt #{attempt}")
232232

233-
if is_retryable_exception?(e)
233+
if is_legacy_retryable_exception?(e)
234234
raise e if attempt > client.max_read_retries || session&.in_transaction?
235235
elsif e.retryable? && !session&.in_transaction?
236236
raise e if attempt > client.max_read_retries

spec/integration/retryable_reads_errors_spec.rb

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,31 +74,42 @@
7474
client.subscribe(Mongo::Monitoring::CONNECTION_POOL, subscriber)
7575
end
7676

77-
it "retries on PoolClearedError" do
78-
# After the first find fails, the pool is paused and retry is triggered.
79-
# Now, a race is started between the second find acquiring a connection,
80-
# and the first retrying the read. Now, retry reads cause the cluster to
81-
# be rescanned and the pool to be unpaused, allowing the second checkout
82-
# to succeed (when it should fail). Therefore we want the second find's
83-
# check out to win the race. This gives the check out a little head start.
84-
allow_any_instance_of(Mongo::Server::ConnectionPool).to receive(:ready).and_wrap_original do |m, *args, &block|
85-
::Utils.wait_for_condition(5) do
86-
# check_out_results should contain:
87-
# - find1 connection check out successful
88-
# - pool cleared
89-
# - find2 connection check out failed
90-
# We wait here for the third event to happen before we ready the pool.
91-
cmap_events.select do |e|
92-
event_types.include?(e.class)
93-
end.length >= 3
77+
shared_examples_for 'retries on PoolClearedError' do
78+
it "retries on PoolClearedError" do
79+
# After the first find fails, the pool is paused and retry is triggered.
80+
# Now, a race is started between the second find acquiring a connection,
81+
# and the first retrying the read. Now, retry reads cause the cluster to
82+
# be rescanned and the pool to be unpaused, allowing the second checkout
83+
# to succeed (when it should fail). Therefore we want the second find's
84+
# check out to win the race. This gives the check out a little head start.
85+
allow_any_instance_of(Mongo::Server::ConnectionPool).to receive(:ready).and_wrap_original do |m, *args, &block|
86+
::Utils.wait_for_condition(5) do
87+
# check_out_results should contain:
88+
# - find1 connection check out successful
89+
# - pool cleared
90+
# - find2 connection check out failed
91+
# We wait here for the third event to happen before we ready the pool.
92+
cmap_events.select do |e|
93+
event_types.include?(e.class)
94+
end.length >= 3
95+
end
96+
m.call(*args, &block)
9497
end
95-
m.call(*args, &block)
98+
threads.map(&:join)
99+
expect(check_out_results[0]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckedOut)
100+
expect(check_out_results[1]).to be_a(Mongo::Monitoring::Event::Cmap::PoolCleared)
101+
expect(check_out_results[2]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckOutFailed)
102+
expect(find_events.length).to eq(3)
96103
end
97-
threads.map(&:join)
98-
expect(check_out_results[0]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckedOut)
99-
expect(check_out_results[1]).to be_a(Mongo::Monitoring::Event::Cmap::PoolCleared)
100-
expect(check_out_results[2]).to be_a(Mongo::Monitoring::Event::Cmap::ConnectionCheckOutFailed)
101-
expect(find_events.length).to eq(3)
104+
end
105+
106+
it_behaves_like 'retries on PoolClearedError'
107+
108+
context 'legacy read retries' do
109+
110+
let(:client) { authorized_client.with(options.merge(retry_reads: false, max_read_retries: 1)) }
111+
112+
it_behaves_like 'retries on PoolClearedError'
102113
end
103114

104115
after do

0 commit comments

Comments
 (0)