This repository has been archived by the owner on Jan 15, 2024. It is now read-only.
/
errors.rb
183 lines (154 loc) · 5.72 KB
/
errors.rb
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
module Moped
module Errors
# Mongo's exceptions are sparsely documented, but this is the most accurate
# source of information on error codes.
ERROR_REFERENCE = "https://github.com/mongodb/mongo/blob/master/docs/errors.md"
# Raised when the connection pool is saturated and no new connection is
# reaped during the wait time.
class PoolSaturated < RuntimeError; end
# Raised when attempting to checkout a connection on a thread that already
# has a connection checked out.
class ConnectionInUse < RuntimeError; end
# Raised when attempting to checkout a pinned connection from the pool but
# it is already in use by another object on the same thread.
class PoolTimeout < RuntimeError; end
# Generic error class for exceptions related to connection failures.
class ConnectionFailure < StandardError; end
# Raised when a database name is invalid.
class InvalidDatabaseName < StandardError; end
# Raised when a Mongo URI is invalid.
class InvalidMongoURI < StandardError; end
# Raised when providing an invalid string from an object id.
class InvalidObjectId < StandardError
# Create the new error.
#
# @example Create the new error.
# InvalidObjectId.new("test")
#
# @param [ String ] string The provided id.
#
# @since 1.0.0
def initialize(string)
super("'#{string}' is not a valid object id.")
end
end
# Generic error class for exceptions generated on the remote MongoDB
# server.
class MongoError < StandardError
# @attribute [r] details The details about the error.
# @attribute [r] command The command that generated the error.
attr_reader :details, :command
# Create a new operation failure exception.
#
# @example Create the new error.
# MongoError.new(command, details)
#
# @param [ Object ] command The command that generated the error.
# @param [ Hash ] details The details about the error.
#
# @since 1.0.0
def initialize(command, details)
@command, @details = command, details
super(build_message)
end
private
# Build the error message.
#
# @api private
#
# @example Build the message.
# error.build_message
#
# @return [ String ] The message.
#
# @since 1.0.0
def build_message
"The operation: #{command.inspect}\n#{error_message}"
end
# Get the error message.
#
# @api private
#
# @example Get the error message.
# error.error_message
#
# @return [ String ] The message.
#
# @since 1.0.0
def error_message
err = details["err"] || details["errmsg"] || details["$err"]
if code = details["code"]
"failed with error #{code}: #{err.inspect}\n\n" <<
"See #{ERROR_REFERENCE}\nfor details about this error."
elsif code = details["assertionCode"]
assertion = details["assertion"]
"failed with error #{code}: #{assertion.inspect}\n\n" <<
"See #{ERROR_REFERENCE}\nfor details about this error."
else
"failed with error #{err.inspect}"
end
end
end
# Classes of errors that should not disconnect connections.
class DoNotDisconnect < MongoError; end
# Classes of errors that could be caused by a replica set reconfiguration.
class PotentialReconfiguration < MongoError
# Not master error codes.
NOT_MASTER = [ 13435, 13436, 10009 ]
# Error codes received around reconfiguration
CONNECTION_ERRORS_RECONFIGURATION = [ 15988, 10276, 11600, 9001, 13639, 10009 ]
# Replica set reconfigurations can be either in the form of an operation
# error with code 13435, or with an error message stating the server is
# not a master. (This encapsulates codes 10054, 10056, 10058)
def reconfiguring_replica_set?
err = details["err"] || details["errmsg"] || details["$err"] || ""
NOT_MASTER.include?(details["code"]) || err.include?("not master")
end
def connection_failure?
CONNECTION_ERRORS_RECONFIGURATION.include?(details["code"])
end
# Is the error due to a namespace not being found?
#
# @example Is the namespace not found?
# error.ns_not_found?
#
# @return [ true, false ] If the namespace was not found.
#
# @since 2.0.0
def ns_not_found?
details["errmsg"] == "ns not found"
end
# Is the error due to a namespace not existing?
#
# @example Doest the namespace not exist?
# error.ns_not_exists?
#
# @return [ true, false ] If the namespace was not found.
#
# @since 2.0.0
def ns_not_exists?
details["errmsg"] =~ /namespace does not exist/
end
end
# Exception raised when authentication fails.
class AuthenticationFailure < DoNotDisconnect; end
# Exception class for exceptions generated as a direct result of an
# operation, such as a failed insert or an invalid command.
class OperationFailure < PotentialReconfiguration; end
# Exception raised on invalid queries.
class QueryFailure < PotentialReconfiguration; end
# Exception raised if the cursor could not be found.
class CursorNotFound < DoNotDisconnect
def initialize(operation, cursor_id)
super(operation, {"errmsg" => "cursor #{cursor_id} not found"})
end
end
# @api private
#
# Internal exception raised by Node#ensure_primary and captured by
# Cluster#with_primary.
class ReplicaSetReconfigured < DoNotDisconnect; end
# Tag applied to unhandled exceptions on a node.
module SocketError; end
end
end