-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOrderProcessorActor.cs
160 lines (148 loc) · 5.57 KB
/
OrderProcessorActor.cs
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Text;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Event;
using Newtonsoft.Json;
using Stripe;
using Polly;
namespace ActorSupervisionDeepDive {
public class PlaceOrder {
public int AccountId { get; }
public int ItemId { get; }
public int Quantity { get; }
public int ExtPrice { get; }
public PlaceOrder(int accountId, int itemId, int quantity, int extPrice) {
AccountId = accountId;
ItemId = itemId;
Quantity = quantity;
ExtPrice = extPrice;
}
}
public class OrderPlaced {
public string OrderId { get; }
public PlaceOrder OrderInfo { get; set; }
public OrderPlaced(string orderId, PlaceOrder orderInfo) {
OrderId = orderId;
OrderInfo = orderInfo;
}
}
public class ChargeCreditCard {
public int Amount { get; }
public ChargeCreditCard(int amount) {
Amount = amount;
}
}
class AccountCharged {
public ChargeCreditCard ChargeInfo { get; }
public bool Success { get; }
public AccountCharged(ChargeCreditCard chargeInfo, bool success) {
ChargeInfo = chargeInfo;
Success = success;
}
}
public class OrderProcessorActor : ReceiveActor {
private readonly ILoggingAdapter _logger = Context.GetLogger();
public OrderProcessorActor() {
Receive<PlaceOrder>(placeOrder => PlaceOrderHandler(placeOrder));
Receive<OrderPlaced>(orderPlaced => OrderPlacedHandler(orderPlaced));
Receive<AccountCharged>(accountCharged => AccountChargedHandler(accountCharged));
}
private void PlaceOrderHandler(PlaceOrder placeOrder) {
var orderActor = Context.ActorOf(
Props.Create(
() => new OrderActor(
(int)DateTime.Now.Ticks)),
"orderActor" + DateTime.Now.Ticks);
orderActor.Tell(placeOrder);
}
private void OrderPlacedHandler(OrderPlaced orderPlaced) {
var accountActor = Context.ActorOf(
Props.Create(
() => new AccountActor(
orderPlaced.OrderInfo.AccountId)),
"accountActor" + orderPlaced.OrderInfo.AccountId);
accountActor.Tell(new ChargeCreditCard(orderPlaced.OrderInfo.ExtPrice));
}
private void AccountChargedHandler(AccountCharged accountCharged) {
if (accountCharged.Success) {
_logger.Info("Account charged!\n{0}",
JsonConvert.SerializeObject(accountCharged));
// Sends to TestActor (Test) or CustomerActor (Production)
Context.Parent.Tell(accountCharged);
}
else {
_logger.Error("Error! Account not charged!");
// Sends to TestActor (Test) or CustomerActor (Production)
Context.Parent.Tell(accountCharged);
}
}
protected override SupervisorStrategy SupervisorStrategy() {
return new OneForOneStrategy(
Decider.From(x => {
if (x is StripeException) return Directive.Resume;
return Directive.Restart;
})
);
}
}
class OrderActor : ReceiveActor {
public int OrderId { get; }
public OrderActor(int orderId) {
OrderId = orderId;
Receive<PlaceOrder>(placeOrder => PlaceOrderHandler(placeOrder));
}
public void PlaceOrderHandler(PlaceOrder placeOrder) {
Context.Parent.Tell(
new OrderPlaced(DateTime.Now.Ticks.ToString(), placeOrder));
}
}
public class AccountActor : ReceiveActor {
public int AccountId { get; }
private readonly IStripeGateway _stripeGateway = new StripeGateway();
private readonly ILoggingAdapter _logger = Context.GetLogger();
public AccountActor(int accountId) {
AccountId = accountId;
Receive<ChargeCreditCard>(
chargeCreditCard => ChargeCreditCardHandler(chargeCreditCard));
}
private void ChargeCreditCardHandler(ChargeCreditCard chargeCreditCard) {
StripeCharge stripeCharge = null;
try {
stripeCharge = _stripeGateway
.CreateCharge(chargeCreditCard.Amount);
if (stripeCharge != null)
Context.Parent.Tell(new AccountCharged(chargeCreditCard, true));
}
catch (Exception) {
Context.Parent.Tell(new AccountCharged(chargeCreditCard, false));
throw;
}
}
protected override void PostStop() {
_logger.Warning("AccountActor stopped!");
base.PostStop();
}
}
internal interface IStripeGateway {
StripeCharge CreateCharge(int amount);
}
public class StripeGateway : IStripeGateway {
public StripeCharge CreateCharge(int amount) {
if (amount < 0) {
throw new StripeException(
System.Net.HttpStatusCode.OK,
new StripeError() {
Code = "card_error"
}, "Can't charge card a negative value");
}
return new StripeCharge() {
Amount = amount,
Captured = true
};
}
}
}