Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
StackExchange.Redis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
StackExchange.Redis
Commits
11e1482b
Commit
11e1482b
authored
Jul 13, 2018
by
Marc Gravell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perform asunc timeouts in bridge heartbeats
parent
267ec00d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
77 additions
and
19 deletions
+77
-19
AsyncTests.cs
StackExchange.Redis.Tests/AsyncTests.cs
+20
-1
CommandFlags.cs
...kExchange.Redis/StackExchange/Redis/Enums/CommandFlags.cs
+2
-0
Message.cs
StackExchange.Redis/StackExchange/Redis/Message.cs
+26
-1
PhysicalConnection.cs
...kExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
+24
-1
ResultBox.cs
StackExchange.Redis/StackExchange/Redis/ResultBox.cs
+5
-16
No files found.
StackExchange.Redis.Tests/AsyncTests.cs
View file @
11e1482b
using
System.Linq
;
using
System
;
using
System.Linq
;
using
System.Threading.Tasks
;
using
Xunit
;
using
Xunit.Abstractions
;
...
...
@@ -40,5 +42,22 @@ public void AsyncTasksReportFailureIfServerUnavailable()
}
}
#endif
[
Fact
]
public
async
Task
AsyncTimeoutIsNoticed
()
{
using
(
var
conn
=
Create
(
syncTimeout
:
1000
))
{
var
db
=
conn
.
GetDatabase
();
var
ex
=
await
Assert
.
ThrowsAsync
<
RedisTimeoutException
>(
async
()
=>
{
await
db
.
ExecuteAsync
(
"client"
,
"pause"
,
2500
);
// client pause returns immediately
await
db
.
PingAsync
();
// but *subsequent* operations are paused
});
Assert
.
Contains
(
"Timeout awaiting response"
,
ex
.
Message
);
Writer
.
WriteLine
(
ex
.
Message
);
}
}
}
}
StackExchange.Redis/StackExchange/Redis/Enums/CommandFlags.cs
View file @
11e1482b
...
...
@@ -62,5 +62,7 @@ public enum CommandFlags
/// Indicates that script-related operations should use EVAL, not SCRIPT LOAD + EVALSHA
/// </summary>
NoScriptCache
=
512
,
// 1024: used for timed-out; never user-specified, so not visible on the public API
}
}
StackExchange.Redis/StackExchange/Redis/Message.cs
View file @
11e1482b
...
...
@@ -49,10 +49,12 @@ internal abstract class Message : ICompletable
public
readonly
int
Db
;
internal
const
CommandFlags
InternalCallFlag
=
(
CommandFlags
)
128
;
protected
RedisCommand
command
;
private
const
CommandFlags
AskingFlag
=
(
CommandFlags
)
32
,
ScriptUnavailableFlag
=
(
CommandFlags
)
256
;
ScriptUnavailableFlag
=
(
CommandFlags
)
256
,
TimedOutFlag
=
(
CommandFlags
)
1024
;
private
const
CommandFlags
MaskMasterServerPreference
=
CommandFlags
.
DemandMaster
|
CommandFlags
.
DemandSlave
...
...
@@ -612,11 +614,34 @@ internal void SetEnqueued()
performance
?.
SetEnqueued
();
}
internal
void
SetRequestSent
()
{
Status
=
CommandStatus
.
Sent
;
_writeTickCount
=
Environment
.
TickCount
;
// note this might be reset if we resend a message, cluster-moved etc; I'm OK with that
performance
?.
SetRequestSent
();
}
// the time (ticks) at which this message was considered written
private
int
_writeTickCount
;
internal
bool
HasTimedOut
(
int
now
,
int
timeoutMilliseconds
,
out
int
millisecondsTaken
)
{
if
((
flags
&
TimedOutFlag
)
==
0
)
{
millisecondsTaken
=
unchecked
(
now
-
_writeTickCount
);
// note: we can't just check "if sent < cutoff" because of wrap-aro
if
(
millisecondsTaken
>=
timeoutMilliseconds
)
{
flags
|=
TimedOutFlag
;
// note: we don't remove it from the queue - still might need to marry it up; but: it is toast
return
true
;
}
}
else
{
millisecondsTaken
=
default
;
}
return
false
;
}
internal
void
SetAsking
(
bool
value
)
{
...
...
StackExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
View file @
11e1482b
...
...
@@ -489,7 +489,30 @@ internal void GetStormLog(StringBuilder sb)
internal
void
OnBridgeHeartbeat
()
{
Interlocked
.
Exchange
(
ref
lastBeatTickCount
,
Environment
.
TickCount
);
var
now
=
Environment
.
TickCount
;
Interlocked
.
Exchange
(
ref
lastBeatTickCount
,
now
);
lock
(
_writtenAwaitingResponse
)
{
if
(
_writtenAwaitingResponse
.
Count
!=
0
)
{
bool
includeDetail
=
Multiplexer
.
IncludeDetailInExceptions
;
var
server
=
Bridge
.
ServerEndPoint
;
var
timeout
=
Multiplexer
.
TimeoutMilliseconds
;
foreach
(
var
msg
in
_writtenAwaitingResponse
)
{
if
(
msg
.
HasTimedOut
(
now
,
timeout
,
out
var
elapsed
))
{
var
timeoutEx
=
ExceptionFactory
.
Timeout
(
includeDetail
,
$"Timeout awaiting response (
{
elapsed
}
ms elapsed, timeout is
{
timeout
}
ms)"
,
msg
,
server
);
msg
.
SetException
(
timeoutEx
);
// tell the message that it is doomed
Bridge
.
CompleteSyncOrAsync
(
msg
);
// prod it - kicks off async continuations etc
}
// note: it is important that we **do not** remove the message unless we're tearing down the socket; that
// would disrupt the chain for MatchResult; we just pre-emptively abort the message from the caller's
// perspective, and set a flag on the message so we don't keep doing it
}
}
}
}
internal
void
OnInternalError
(
Exception
exception
,
[
CallerMemberName
]
string
origin
=
null
)
...
...
StackExchange.Redis/StackExchange/Redis/ResultBox.cs
View file @
11e1482b
...
...
@@ -7,20 +7,9 @@ namespace StackExchange.Redis
{
internal
abstract
partial
class
ResultBox
{
protected
Exception
exception
;
protected
Exception
_
exception
;
public
void
SetException
(
Exception
exception
)
{
this
.
exception
=
exception
;
//try
//{
// throw exception;
//}
//catch (Exception caught)
//{ // stacktrace etc
// this.exception = caught;
//}
}
public
void
SetException
(
Exception
exception
)
=>
_exception
=
exception
;
public
abstract
bool
TryComplete
(
bool
isAsync
);
...
...
@@ -75,9 +64,9 @@ public static void UnwrapAndRecycle(ResultBox<T> box, bool recycle, out T value,
else
{
value
=
box
.
value
;
exception
=
box
.
exception
;
exception
=
box
.
_
exception
;
box
.
value
=
default
(
T
);
box
.
exception
=
null
;
box
.
_
exception
=
null
;
if
(
recycle
)
{
for
(
int
i
=
0
;
i
<
store
.
Length
;
i
++)
...
...
@@ -134,7 +123,7 @@ public override bool TryComplete(bool isAsync)
private
void
Reset
(
object
stateOrCompletionSource
)
{
value
=
default
(
T
);
exception
=
null
;
_
exception
=
null
;
this
.
stateOrCompletionSource
=
stateOrCompletionSource
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment