Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
丁松杰
/
Pole
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
8fc078fb
authored
5 years ago
by
丁松杰
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完成 发送者 发送确认 以及部分 消费者 重试及错误队列的功能
parent
5f7a7238
master
…
v1.0.0
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
176 additions
and
25 deletions
src/Pole.Core/Channels/MpscChannel.cs
src/Pole.Core/Consts.cs
src/Pole.Core/Exceptions/ProducerConfirmTimeOutException.cs
src/Pole.Core/Exceptions/ProducerReceivedNAckException.cs
src/Pole.Core/Serialization/DefaultJsonSerializer.cs
src/Pole.EventBus.Rabbitmq/Client/ConnectionWrapper.cs
src/Pole.EventBus.Rabbitmq/Client/IRabbitMQClient.cs
src/Pole.EventBus.Rabbitmq/Client/ModelWrapper.cs
src/Pole.EventBus.Rabbitmq/Client/RabbitMQClient.cs
src/Pole.EventBus.Rabbitmq/Configuration/ConsumerOptions.cs
src/Pole.EventBus.Rabbitmq/Configuration/RabbitOptions.cs
src/Pole.EventBus.Rabbitmq/Consumer/ConsumerRunner.cs
src/Pole.EventBus.Rabbitmq/Core/EventBusContainer.cs
src/Pole.EventBus.Rabbitmq/Core/RabbitEventBus.cs
src/Pole.EventBus.Rabbitmq/Producer/RabbitProducer.cs
src/Pole.Core/Channels/MpscChannel.cs
View file @
8fc078fb
...
...
@@ -68,10 +68,13 @@ namespace Pole.Core.Channels
{
if
(
consumer
is
null
)
throw
new
NoBindConsumerException
(
GetType
().
Name
);
if
(!
IsChildren
&&
_autoConsuming
==
0
)
ActiveAutoConsumer
();
if
(!
buffer
.
Post
(
data
))
return
await
buffer
.
SendAsync
(
data
);
if
(!
IsChildren
&&
_autoConsuming
==
0
)
ActiveAutoConsumer
();
return
true
;
}
private
void
ActiveAutoConsumer
()
...
...
This diff is collapsed.
Click to expand it.
src/Pole.Core/Consts.cs
View file @
8fc078fb
...
...
@@ -8,5 +8,8 @@ namespace Pole.Core
public
static
class
Consts
{
public
static
ValueTask
ValueTaskDone
=
new
ValueTask
();
public
const
string
ConsumerRetryTimesStr
=
"pole-consumer-retry-times"
;
public
const
string
ConsumerExceptionDetailsStr
=
"pole-consumer-exception-details"
;
}
}
}
This diff is collapsed.
Click to expand it.
src/Pole.Core/Exceptions/ProducerConfirmTimeOutException.cs
0 → 100644
View file @
8fc078fb
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
namespace
Pole.Core.Exceptions
{
public
class
ProducerConfirmTimeOutException
:
Exception
{
public
ProducerConfirmTimeOutException
(
int
timeout
)
:
base
(
$"Producer wait to confirm for
{
timeout
}
seconds, timeout"
)
{
}
}
}
This diff is collapsed.
Click to expand it.
src/Pole.Core/Exceptions/ProducerReceivedNAckException.cs
0 → 100644
View file @
8fc078fb
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
namespace
Pole.Core.Exceptions
{
public
class
ProducerReceivedNAckException
:
Exception
{
public
ProducerReceivedNAckException
():
base
(
"Producer received a NAck, the broker is busy"
)
{
}
}
}
This diff is collapsed.
Click to expand it.
src/Pole.Core/Serialization/DefaultJsonSerializer.cs
0 → 100644
View file @
8fc078fb
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Text.Encodings.Web
;
using
System.Text.Json
;
using
System.Text.Unicode
;
namespace
Pole.Core.Serialization
{
public
class
DefaultJsonSerializer
:
ISerializer
{
static
readonly
JsonSerializerOptions
options
=
new
JsonSerializerOptions
()
{
Encoder
=
JavaScriptEncoder
.
Create
(
UnicodeRanges
.
All
)
};
public
T
Deserialize
<
T
>(
string
json
)
where
T
:
class
,
new
()
{
return
JsonSerializer
.
Deserialize
<
T
>(
json
);
}
public
object
Deserialize
(
byte
[]
bytes
,
Type
type
)
{
return
JsonSerializer
.
Deserialize
(
bytes
,
type
);
}
public
string
Serialize
<
T
>(
T
data
)
where
T
:
class
,
new
()
{
return
JsonSerializer
.
Serialize
(
data
,
options
);
}
public
string
Serialize
(
object
data
,
Type
type
)
{
return
JsonSerializer
.
Serialize
(
data
,
type
,
options
);
}
public
byte
[]
SerializeToUtf8Bytes
<
T
>(
T
data
)
where
T
:
class
,
new
()
{
return
JsonSerializer
.
SerializeToUtf8Bytes
(
data
,
data
.
GetType
(),
options
);
}
public
T
Deserialize
<
T
>(
byte
[]
bytes
)
where
T
:
class
,
new
()
{
return
JsonSerializer
.
Deserialize
<
T
>(
bytes
);
}
public
byte
[]
SerializeToUtf8Bytes
(
object
data
,
Type
type
)
{
return
JsonSerializer
.
SerializeToUtf8Bytes
(
data
,
type
,
options
);
}
public
object
Deserialize
(
string
json
,
Type
type
)
{
return
JsonSerializer
.
Deserialize
(
json
,
type
);
}
}
}
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Client/ConnectionWrapper.cs
View file @
8fc078fb
...
...
@@ -6,7 +6,7 @@ namespace Pole.EventBus.RabbitMQ
{
public
class
ConnectionWrapper
{
private
readonly
List
<
ModelWrapper
>
mod
els
=
new
List
<
ModelWrapper
>();
private
readonly
List
<
ModelWrapper
>
chann
els
=
new
List
<
ModelWrapper
>();
private
readonly
IConnection
connection
;
readonly
SemaphoreSlim
semaphoreSlim
=
new
SemaphoreSlim
(
1
);
public
ConnectionWrapper
(
...
...
@@ -22,11 +22,11 @@ namespace Pole.EventBus.RabbitMQ
semaphoreSlim
.
Wait
();
try
{
if
(
mod
els
.
Count
<
Options
.
MasChannelsPerConnection
)
if
(
chann
els
.
Count
<
Options
.
MasChannelsPerConnection
)
{
var
mod
el
=
new
ModelWrapper
(
this
,
connection
.
CreateModel
());
models
.
Add
(
mod
el
);
return
(
true
,
mod
el
);
var
chann
el
=
new
ModelWrapper
(
this
,
connection
.
CreateModel
());
channels
.
Add
(
chann
el
);
return
(
true
,
chann
el
);
}
}
finally
...
...
@@ -37,7 +37,7 @@ namespace Pole.EventBus.RabbitMQ
}
public
void
Return
(
ModelWrapper
model
)
{
mod
els
.
Remove
(
model
);
chann
els
.
Remove
(
model
);
}
}
}
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Client/IRabbitMQClient.cs
View file @
8fc078fb
...
...
@@ -2,6 +2,6 @@
{
public
interface
IRabbitMQClient
{
ModelWrapper
Pull
Mod
el
();
ModelWrapper
Pull
Chann
el
();
}
}
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Client/ModelWrapper.cs
View file @
8fc078fb
using
Microsoft.Extensions.ObjectPool
;
using
Pole.Core
;
using
Pole.Core.Exceptions
;
using
RabbitMQ.Client
;
using
System
;
...
...
@@ -17,14 +19,31 @@ namespace Pole.EventBus.RabbitMQ
{
Connection
=
connectionWrapper
;
Model
=
model
;
var
consumeRetryTimes
=
0
;
var
consumeRetryTimesStr
=
consumeRetryTimes
.
ToString
();
persistentProperties
=
Model
.
CreateBasicProperties
();
persistentProperties
.
Persistent
=
true
;
persistentProperties
.
Headers
.
Add
(
Consts
.
ConsumerRetryTimesStr
,
consumeRetryTimesStr
);
noPersistentProperties
=
Model
.
CreateBasicProperties
();
noPersistentProperties
.
Persistent
=
false
;
noPersistentProperties
.
Headers
.
Add
(
Consts
.
ConsumerRetryTimesStr
,
consumeRetryTimesStr
);
}
public
void
Publish
(
byte
[]
msg
,
string
exchange
,
string
routingKey
,
bool
persistent
=
true
)
{
Model
.
ConfirmSelect
();
Model
.
BasicPublish
(
exchange
,
routingKey
,
persistent
?
persistentProperties
:
noPersistentProperties
,
msg
);
if
(!
Model
.
WaitForConfirms
(
TimeSpan
.
FromSeconds
(
Connection
.
Options
.
ProducerConfirmWaitTimeoutSeconds
),
out
bool
isTimeout
))
{
if
(
isTimeout
)
{
throw
new
ProducerConfirmTimeOutException
(
Connection
.
Options
.
ProducerConfirmWaitTimeoutSeconds
);
}
else
{
throw
new
ProducerReceivedNAckException
();
}
}
}
public
void
Dispose
()
{
...
...
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Client/RabbitMQClient.cs
View file @
8fc078fb
...
...
@@ -22,7 +22,7 @@ namespace Pole.EventBus.RabbitMQ
pool
=
new
DefaultObjectPool
<
ModelWrapper
>(
new
ModelPooledObjectPolicy
(
connectionFactory
,
options
));
}
public
ModelWrapper
Pull
Mod
el
()
public
ModelWrapper
Pull
Chann
el
()
{
var
result
=
pool
.
Get
();
if
(
result
.
Pool
is
null
)
...
...
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Configuration/ConsumerOptions.cs
View file @
8fc078fb
...
...
@@ -10,8 +10,16 @@
/// </summary>
public
bool
AutoAck
{
get
;
set
;
}
/// <summary>
/// 消息处理失败是否重回队列
还是不停重发
/// 消息处理失败是否重回队列
/// </summary>
public
bool
Reenqueue
{
get
;
set
;
}
/// <summary>
/// 错误队列后缀
/// </summary>
public
string
ErrorQueueSuffix
{
get
;
set
;
}
/// <summary>
/// 消息处理失败最大重试次数
/// </summary>
public
int
MaxReenqueueTimes
{
get
;
set
;
}
}
}
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Configuration/RabbitOptions.cs
View file @
8fc078fb
...
...
@@ -12,7 +12,7 @@ namespace Pole.EventBus.RabbitMQ
/// <summary>
/// 目前为一个连接 当消息数量非常大时,单个TCP连接的运输能力有限,可以修改这个最大连接数提高运输能力
/// </summary>
public
int
MaxConnection
{
get
;
set
;
}
=
1
;
public
int
MaxConnection
{
get
;
set
;
}
=
1
0
;
/// <summary>
/// 消费者批量处理每次处理的最大消息量
/// </summary>
...
...
@@ -22,6 +22,10 @@ namespace Pole.EventBus.RabbitMQ
/// </summary>
public
int
CunsumerMaxMillisecondsInterval
{
get
;
set
;
}
=
1000
;
/// <summary>
/// 消费者批量处理每次处理的最大延时
/// </summary>
public
int
ProducerConfirmWaitTimeoutSeconds
{
get
;
set
;
}
=
5
;
/// <summary>
/// exchange 和 queue 名称的前缀
/// </summary>
public
string
Prefix
=
"Pole_"
;
...
...
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Consumer/ConsumerRunner.cs
View file @
8fc078fb
...
...
@@ -7,12 +7,15 @@ using System;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Threading.Tasks
;
using
Pole.Core
;
using
Pole.Core.Serialization
;
namespace
Pole.EventBus.RabbitMQ
{
public
class
ConsumerRunner
{
readonly
IMpscChannel
<
BasicDeliverEventArgs
>
mpscChannel
;
readonly
ISerializer
serializer
;
public
ConsumerRunner
(
IRabbitMQClient
client
,
IServiceProvider
provider
,
...
...
@@ -21,6 +24,7 @@ namespace Pole.EventBus.RabbitMQ
{
Client
=
client
;
Logger
=
provider
.
GetService
<
ILogger
<
ConsumerRunner
>>();
serializer
=
provider
.
GetService
<
ISerializer
>();
mpscChannel
=
provider
.
GetService
<
IMpscChannel
<
BasicDeliverEventArgs
>>();
mpscChannel
.
BindConsumer
(
BatchExecuter
);
Consumer
=
consumer
;
...
...
@@ -36,14 +40,14 @@ namespace Pole.EventBus.RabbitMQ
private
bool
isFirst
=
true
;
public
Task
Run
()
{
Model
=
Client
.
Pull
Mod
el
();
Model
=
Client
.
Pull
Chann
el
();
mpscChannel
.
Config
(
Model
.
Connection
.
Options
.
CunsumerMaxBatchSize
,
Model
.
Connection
.
Options
.
CunsumerMaxMillisecondsInterval
);
if
(
isFirst
)
{
isFirst
=
false
;
Model
.
Model
.
ExchangeDeclare
(
Consumer
.
EventBus
.
Exchange
,
"direct"
,
true
);
Model
.
Model
.
ExchangeDeclare
(
Queue
.
Queue
,
"direct"
,
true
);
Model
.
Model
.
ExchangeBind
(
Consumer
.
EventBus
.
Exchange
,
Queue
.
Queue
,
string
.
Empty
);
Model
.
Model
.
ExchangeBind
(
Consumer
.
EventBus
.
Exchange
,
Queue
.
Queue
,
string
.
Empty
);
Model
.
Model
.
QueueDeclare
(
Queue
.
Queue
,
true
,
false
,
false
,
null
);
Model
.
Model
.
QueueBind
(
Queue
.
Queue
,
Queue
.
Queue
,
string
.
Empty
);
}
...
...
@@ -98,21 +102,51 @@ namespace Pole.EventBus.RabbitMQ
try
{
await
Consumer
.
Notice
(
ea
.
Body
);
}
catch
(
Exception
exception
)
{
Logger
.
LogError
(
exception
,
$"An error occurred in
{
Queue
.
Queue
}
, routing path
{
Consumer
.
EventBus
.
Exchange
}
->
{
Queue
.
Queue
}
->
{
Queue
.
Queue
}
"
);
await
ProcessComsumerErrors
(
ea
,
exception
);
}
if
(!
Consumer
.
Config
.
AutoAck
)
{
Model
.
Model
.
BasicAck
(
ea
.
DeliveryTag
,
false
);
}
}
catch
(
Exception
exception
)
private
async
Task
ProcessComsumerErrors
(
BasicDeliverEventArgs
ea
,
Exception
exception
)
{
Logger
.
LogError
(
exception
.
InnerException
??
exception
,
$"An error occurred in
{
Consumer
.
EventBus
.
Exchange
}
-
{
Queue
}
"
);
if
(
Consumer
.
Config
.
Reenqueue
)
{
await
Task
.
Delay
(
1000
);
if
(
ea
.
BasicProperties
.
Headers
.
TryGetValue
(
Consts
.
ConsumerRetryTimesStr
,
out
object
retryTimesObj
))
{
var
retryTimes
=
Convert
.
ToInt32
(
retryTimesObj
);
if
(
retryTimes
<=
Consumer
.
Config
.
MaxReenqueueTimes
)
{
retryTimes
++;
ea
.
BasicProperties
.
Headers
[
Consts
.
ConsumerRetryTimesStr
]
=
retryTimes
;
ea
.
BasicProperties
.
Headers
[
Consts
.
ConsumerExceptionDetailsStr
]
=
serializer
.
Serialize
(
exception
,
typeof
(
Exception
));
await
Task
.
Delay
((
int
)
Math
.
Pow
(
2
,
retryTimes
)
*
1000
).
ContinueWith
((
task
)
=>
{
Model
.
Model
.
BasicReject
(
ea
.
DeliveryTag
,
true
);
});
}
else
{
var
errorQueueName
=
$"
{
Queue
.
Queue
}{
Consumer
.
Config
.
ErrorQueueSuffix
}
"
;
var
errorExchangeName
=
$"
{
Queue
.
Queue
}{
Consumer
.
Config
.
ErrorQueueSuffix
}
"
;
Model
.
Model
.
ExchangeDeclare
(
errorExchangeName
,
"direct"
,
true
);
Model
.
Model
.
QueueDeclare
(
errorQueueName
,
true
,
false
,
false
,
null
);
Model
.
Model
.
QueueBind
(
errorQueueName
,
errorExchangeName
,
string
.
Empty
);
}
if
(!
Consumer
.
Config
.
AutoAck
)
{
Model
.
Model
.
BasicAck
(
ea
.
DeliveryTag
,
false
);
}
}
}
}
public
void
Close
()
{
Model
?.
Dispose
();
...
...
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Core/EventBusContainer.cs
View file @
8fc078fb
...
...
@@ -42,19 +42,19 @@ namespace Pole.EventBus.RabbitMQ
AddEventAndEventHandlerInfoList
(
eventList
,
evenHandlertList
);
foreach
(
var
(
type
,
config
)
in
eventList
)
{
var
eventName
=
string
.
IsNullOrEmpty
(
config
.
EventName
)
?
type
.
Name
:
config
.
EventName
;
var
eventBus
=
CreateEventBus
(
eventName
,
rabbitOptions
.
Prefix
,
2
,
tru
e
,
true
,
true
).
BindEvent
(
type
,
eventName
);
var
eventName
=
string
.
IsNullOrEmpty
(
config
.
EventName
)
?
type
.
Name
.
ToLower
()
:
config
.
EventName
;
var
eventBus
=
CreateEventBus
(
eventName
,
rabbitOptions
.
Prefix
,
1
,
fals
e
,
true
,
true
).
BindEvent
(
type
,
eventName
);
await
eventBus
.
AddGrainConsumer
<
string
>();
}
foreach
(
var
(
type
,
config
)
in
evenHandlertList
)
{
var
eventName
=
string
.
IsNullOrEmpty
(
config
.
EventName
)
?
type
.
Name
:
config
.
EventName
;
var
eventBus
=
CreateEventBus
(
eventName
,
rabbitOptions
.
Prefix
,
2
,
tru
e
,
true
,
true
).
BindEvent
(
type
,
eventName
);
var
eventName
=
string
.
IsNullOrEmpty
(
config
.
EventName
)
?
type
.
Name
.
ToLower
()
:
config
.
EventName
;
var
eventBus
=
CreateEventBus
(
eventName
,
rabbitOptions
.
Prefix
,
1
,
fals
e
,
true
,
true
).
BindEvent
(
type
,
eventName
);
await
eventBus
.
AddGrainConsumer
<
string
>();
}
}
public
RabbitEventBus
CreateEventBus
(
string
exchange
,
string
routePrefix
,
int
lBCount
=
1
,
bool
autoAck
=
tru
e
,
bool
reenqueue
=
true
,
bool
persistent
=
true
)
public
RabbitEventBus
CreateEventBus
(
string
exchange
,
string
routePrefix
,
int
lBCount
=
1
,
bool
autoAck
=
fals
e
,
bool
reenqueue
=
true
,
bool
persistent
=
true
)
{
return
new
RabbitEventBus
(
observerUnitContainer
,
this
,
exchange
,
routePrefix
,
lBCount
,
autoAck
,
reenqueue
,
persistent
);
}
...
...
@@ -63,7 +63,7 @@ namespace Pole.EventBus.RabbitMQ
if
(
eventBusDictionary
.
TryAdd
(
bus
.
Event
,
bus
))
{
eventBusList
.
Add
(
bus
);
using
var
channel
=
rabbitMQClient
.
Pull
Mod
el
();
using
var
channel
=
rabbitMQClient
.
Pull
Chann
el
();
channel
.
Model
.
ExchangeDeclare
(
bus
.
Exchange
,
"direct"
,
true
);
return
Task
.
CompletedTask
;
}
...
...
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Core/RabbitEventBus.cs
View file @
8fc078fb
...
...
@@ -32,6 +32,8 @@ namespace Pole.EventBus.RabbitMQ
{
AutoAck
=
autoAck
,
Reenqueue
=
reenqueue
,
ErrorQueueSuffix
=
"_error"
,
MaxReenqueueTimes
=
10
};
}
public
IRabbitEventBusContainer
Container
{
get
;
}
...
...
This diff is collapsed.
Click to expand it.
src/Pole.EventBus.Rabbitmq/Producer/RabbitProducer.cs
View file @
8fc078fb
...
...
@@ -17,8 +17,8 @@ namespace Pole.EventBus.RabbitMQ
}
public
ValueTask
Publish
(
byte
[]
bytes
,
string
hashKey
)
{
using
var
model
=
rabbitMQClient
.
PullMod
el
();
mod
el
.
Publish
(
bytes
,
publisher
.
Exchange
,
publisher
.
GetRoute
(
hashKey
),
publisher
.
Persistent
);
using
var
channel
=
rabbitMQClient
.
PullChann
el
();
chann
el
.
Publish
(
bytes
,
publisher
.
Exchange
,
publisher
.
GetRoute
(
hashKey
),
publisher
.
Persistent
);
return
Consts
.
ValueTaskDone
;
}
}
...
...
This diff is collapsed.
Click to expand it.
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