Can the order filling be executed synchronously with fix protocol? Since protocol by it's nature is async I am thinking to use TaskCompletionSource. However I experience problem in picking up unique identifier. OrderId won't work in case when required field is missing server will respond with BusinessMessageReject and I won't know how to set task to cancelled or failed. I thought to use msgSeq as unique identifier. However, at the time of sending and I don't know it, because it's handled by QuickFixN internally. Plus in case of connection reset seqNum will be reset too. There are possibly edge cases like to deal somehow with long running messages.
Please see below code attached. I am omitting other methods, so you can get the idea of what I am trying to achieve. Let me know if it's waste of time.
class FixClient : IApplication
{
private ConcurrentDictionary<string, TaskCompletionSource<ExecutionReport>> _currentOrdersUnderProcessing = new ConcurrentDictionary<string, TaskCompletionSource<ExecutionReport>>();
// In case when some required field is missing
public void OnMessage(BusinessMessageReject message, SessionID sessionID)
{
// how can I can extract needed key, if there is no OrderId in the response
var orderId = ""; // how?
if (_currentOrdersUnderProcessing.TryRemove(orderId, out var taskCompletionSource))
{
taskCompletionSource.SetException(new Exception("Couldn't execute order"));
}
}
public void OnMessage(ExecutionReport message, SessionID sessionID)
{
var orderId = message.GetField(11); // ClOrdID field
if (_currentOrdersUnderProcessing.TryRemove(orderId, out var taskCompletionSource))
{
taskCompletionSource.SetResult(message);
}
}
public Task SendNewBuyMarketOrderAsync(string symbol)
{
var orderId = Guid.NewGuid().ToString();
var message = new NewOrderSingle(uniqueOrderId, instructionsForOrderHandling, symbol, side, transactionTime, orderType);
if (QuickFix.Session.SendToTarget(message, sessionId)) // if send successfully
{
var tsc = new TaskCompletionSource<ExecutionReport>();
_currentOrdersUnderProcessing.TryAdd(orderId, tsc)
return tsc.Task;
}
else
{
return Task.FromException(new Exception("Couldn't place order"));
}
}
}
Related
I am working on a web application where the user's connection times out after a specific time (say 20 seconds). For long running requests I have to return a default message ("your request is under process") and then send an email to the user with the actual result.
I couldn't do this with spring web because I didn't know how to specify a timeout in the controller (with customized messages per request) and at the same time let other requests come through and be processed too. That's why I used spring web-flux which has a timeout operator for both Mono and Flux types.
To make the requested process run in a different thread, I have used Sinks. One to receive requests and one to publish the results. My problem is that the response sink can only return one result and subsequent calls to the URL returns an empty response. For example the first call to /reactive/getUser/123456789 returns the user object but subsequent calls return empty.
I'm not sure if the problem is with the Sink I have used or with how I am getting data from it. In the sample code I have used responseSink.asFlux().next() but I have also tried .single(), .toMono(), .take(1). to no avail. I get the same result.
#RequestMapping("/reactive")
#RestController
class SampleController #Autowired constructor(private val externalService: ExternalService) {
private val requestSink = Sinks.many().multicast().onBackpressureBuffer<String>()
private val responseSink = Sinks.many().multicast().onBackpressureBuffer<AppUser>()
init {
requestSink.asFlux()
.map { phoneNumber -> externalService.findByIdOrNull(phoneNumber) }
.doOnNext {
if (it != null) {
responseSink.tryEmitNext(it)
} else {
responseSink.tryEmitError(Throwable("didn't find a value for that phone number"))
}
}
.subscribe()
}
#GetMapping("/getUser/{phoneNumber}")
fun getUser(#PathVariable phoneNumber: String): Mono<String> {
requestSink.tryEmitNext(phoneNumber)
return responseSink.asFlux()
.next()
.map { it.toString() }
.timeout(Duration.ofSeconds(20), Mono.just("processing your request"))
}
}
I am trying to implement skill based matchmaking using Photon in Unity. It seems
I got most of this code from the documentation and it works but not well.
The problem is that you can't use JoinOrCreate() with the sql lobby type so my logic here is try and find a room, if it fails create one.
void init()
{
_client = Game.Context.GetComponent<SocketConnectionManager>().client;
joinRoom();
}
public void joinRoom()
{
TypedLobby sqlLobby = new TypedLobby("skillLobby", LobbyType.SqlLobby);
string sqlLobbyFilter = "C0 BETWEEN 100 AND 200";
_client.OpJoinRandomRoom(null, MatchMaker.MaxPlayers, MatchmakingMode.FillRoom, sqlLobby, sqlLobbyFilter);
}
public void createRoom()
{
RoomOptions o = new RoomOptions();
o.MaxPlayers = MatchMaker.MaxPlayers;
o.CustomRoomProperties = new Hashtable() { { "C0", Game.Me.getInt("trophies") } };
o.CustomRoomPropertiesForLobby = new string[] { "C0" }; // this makes "C0" available in the lobby
TypedLobby sqlLobby = new TypedLobby("skillLobby", LobbyType.SqlLobby);
_client.OpCreateRoom("", o, sqlLobby);
}
private void onEvent(EventData obj)
{
if (_client.CurrentRoom != null)
{
if (_client.CurrentRoom.PlayerCount >= _client.CurrentRoom.MaxPlayers)
{
// sweet I am good to go.
}
}
else
{
createRoom();
}
}
The problem is this is pretty unreliable. Say two players try to find a game at the same time they will both search fail and then both create. Now I have two players sitting in empty rooms instead of playing each other.
Any ideas on a better system?
Thanks all.
Thank you for choosing Photon!
First of all, there are few things that you should understand about Photon:
you can't use JoinOrCreate() with the sql lobby type
This is not correct.
Where did you read such thing?
Did you test this yourself? What did you test exactly?
onEvent (LoadBalancingClient.OnEventAction) callback cannot be used to be notified of a failed join random room operation. Instead, you should make use of the LoadBalancingClient.OnOpResponseAction callback, as follows:
private void OnOpResponse(OperationResponse operationResponse)
{
switch (operationResponse.Code)
{
case OperationCode.JoinRandomGame:
if (operationResponse.ReturnCode == ErrorCode.NoMatchFound)
{
createRoom();
}
break;
}
}
To detect a join event inside a room (local or remote player entered a room):
private void onEvent(EventData eventData)
{
switch (eventData.Code)
{
case EventCode.Join:
int actorNr = (int)eventData[ParameterCode.ActorNr];
PhotonPlayer originatingPlayer = this.GetPlayerWithId(actorNr);
if (originatingPlayer.IsLocal)
{
}
else
{
}
break;
}
}
To answer your question:
Say two players try to find a game at the same time they will both
search fail and then both create.
Any ideas on a better system?
No.
This issue happens only during the development phase where you use a few clients to run some tests. Once you have enough user base you won't notice this issue.
I want to repeat a Single based on the single value emitted in onSuccess(). Here is a working example
import org.reactivestreams.Publisher;
import io.reactivex.Flowable;
import io.reactivex.Single;
import io.reactivex.functions.Function;
public class Temp {
void main() {
Job job = new Job();
Single.just(job)
.map(this::processJob)
.repeatWhen(new Function<Flowable<Object>, Publisher<?>>() {
#Override
public Publisher<?> apply(Flowable<Object> objectFlowable) throws Exception {
// TODO repeat when Single emits false
return null;
}
})
.subscribe();
}
/**
* returns true if process succeeded, false if failed
*/
boolean processJob(Job job) {
return true;
}
class Job {
}
}
I understand how repeatWhen works for Observables by relying on the "complete" notification. However since Single doesn't receive that notification I'm not sure what the Flowable<Object> is really giving me. Also why do I need to return a Publisher from this function?
Instead of relying on a boolean value, you could make your job throw an exception when it fails:
class Job {
var isSuccess: Boolean = false
}
fun processJob(job: Job): String {
if (job.isSuccess) {
return "job succeeds"
} else {
throw Exception("job failed")
}
}
val job = Job()
Single.just(job)
.map { processJob(it) }
.retry() // will resubscribe until your job succeeds
.subscribe(
{ value -> print(value) },
{ error -> print(error) }
)
i saw a small discrepancy in the latest docs and your code, so i did a little digging...
(side note - i think the semantics of retryWhen seem like the more appropriate operator for your case, so i've substituted it in for your usage of repeatWhen. but i think the root of your problem remains the same in either case).
the signature for retryWhen is:
retryWhen(Function<? super Flowable<Throwable>,? extends Publisher<?>> handler)
that parameter is a factory function whose input is a source that emits anytime onError is called upstream, giving you the ability to insert custom retry logic that may be influenced through interrogation of the underlying Throwable. this begins to answer your first question of "I'm not sure what the Flowable<Object> is really giving me" - it shouldn't be Flowable<Object> to begin with, it should be Flowable<Throwable> (for the reason i just described).
so where did Flowable<Object> come from? i managed to reproduce IntelliJ's generation of this code through it's auto-complete feature using RxJava version 2.1.17. upgrading to 2.2.0, however, produces the correct result of Flowable<Throwable>. so, see if upgrading to the latest version generates the correct result for you as well.
as for your second question of "Also why do I need to return a Publisher from this function?" - this is used to determine if re-subscription should happen. if the factory function returns a Publisher that emits a terminal state (ie calls onError() or onComplete()) re-subscription will not happen. however, if onNext() is called, it will. (this also explains why the Publisher isn't typed - the type doesn't matter. the only thing that does matter is what kind of notification it publishes).
another way to rewrite this, incorporating the above, might be as follows:
// just some type to use as a signal to retry
private class SpecialException extends RuntimeException {}
// job processing results in a Completable that either completes or
// doesn't (by way of an exception)
private Completable rxProcessJob(Job job) {
return Completable.complete();
// return Completable.error(new SpecialException());
}
...
rxProcessJob(new Job())
.retryWhen(errors -> {
return errors.flatMap(throwable -> {
if(throwable instanceof SpecialException) {
return PublishProcessor.just(1);
}
return PublishProcessor.error(throwable);
});
})
.subscribe(
() -> {
System.out.println("## onComplete()");
},
error -> {
System.out.println("## onError(" + error.getMessage() + ")");
}
);
i hope that helps!
The accepted answer would work, but is hackish. You don't need to throw an error; simply filter the output of processJob which converts the Single to a Maybe, and then use the repeatWhen handler to decide how many times, or with what delay, you may want to resubscribe. See Kotlin code below from a working example, you should be able to easily translate this to Java.
filter { it }
.repeatWhen { handler ->
handler.zipWith(1..3) { _, i -> i }
.flatMap { retryCount -> Flowable.timer(retryDelay.toDouble().pow(retryCount).toLong(), TimeUnit.SECONDS) }
.doOnNext { log.warn("Retrying...") }
}
I would like to merge two Single<MyData> such that if one of them fails but the other one succeeds then the error of the one that failed and the emission from the other one are reported, and then the resulting Single<MyData> (or Observable<MyData>) completes.
If both Single<MyData> fail then the result should also fail and also be marked as failed.
What I would like to have at the end is:
If both succeed then the emitted values and a producer marked as completed.
If one succeeds and the other fails, the emitted value, the thrown error and the producer marked as complete.
If all fail, the errors and the producer marked as failed.
It's like an 'OR' operation
This is not possible. There is only a single terminal event allowed. The contract for Single is success|error. If you need to receive a next event as well, you should consider to use Observable instead. The contract for Observable is next* complete|error, but you'll still not get a complete.
Observable.mergeDelayError(single1.toObservable(), single2.toObservable())
This can be accomplished with Single.create(SingleOnSubscribe). If your return type is Single<MyData> only one of the responses can be returned, but you could also modify this to instead return a Single<List<MyData>> or some other RxJava structure like Flowable<MyData> that supports multiple returns. In this example, the Single<MyData> returns whichever call returns last because that was the simplest to implement.
public Single<MyData> getCombinedSingle(List<Single<MyData>> singles) {
return Single.create(new SingleOnSubscribe<MyData> {
private boolean encounteredError = false;
private MyData myData;
#Override
public void subscribe(#NonNull Emitter<MyData> emitter) {
List<Disposable> disposables = new ArrayList<>();
Consumer<MyData> myDataConsumer = myData -> {
this.MyData = myData;
checkForFinish(emitter, disposables);
}
Consumer<Throwable> throwableConsumer = throwable -> {
throwable.printStackTrace();
encounteredError = true;
checkForFinish(emitter, disposables);
}
for (Single single: singles) {
disposables.put(single.subscribe(myDataConsumer, throwableConsumer);
}
}
private void checkForFinish(SingleEmitter<MyData> emitter, List<Disposable> disposables) {
if (disposables1.stream().allMatch(Disposable::isDisposed)) {
if (encounteredError) {
emitter.onError(new Throwable());
} else {
emitter.onSuccess(myData);
}
}
}
}
}
This could be modified to return a Throwable from the original Singles if needed.
I'm using MassTransit with Reactive Extensions to stream messages from the queue in batches. Since the behaviour isn't the same as a normal consumer I need to be able to send a message to the error queue if it fails an x number of times.
I've looked through the MassTransit source code and posted on the google groups and can't find an anwser.
Is this available on the ConsumeContext interface? Or is this even possible?
Here is my code. I've removed some of it to make it simpler.
_busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(new Uri("rabbitmq://localhost/"), h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.UseInMemoryScheduler();
cfg.ReceiveEndpoint(host, "customer_update_queue", e =>
{
var _observer = new ObservableObserver<ConsumeContext<Customer>>();
_observer.Buffer(TimeSpan.FromMilliseconds(1000)).Subscribe(OnNext);
e.Observer(_observer);
});
});
private void OnNext(IList<ConsumeContext<Customer>> messages)
{
foreach (var consumeContext in messages)
{
Console.WriteLine("Content: " + consumeContext.Message.Content);
if (consumeContext.Message.RetryCount > 3)
{
// I want to be able to send to the error queue
consumeContext.SendToErrorQueue()
}
}
}
I've found a work around by using the RabbitMQ client mixed with MassTransit. Since I can't throw an exception when using an Observable and therefore no error queue is created. I create it manually using the RabbitMQ client like below.
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";
factory.UserName = "guest";
factory.Password = "guest";
using (IConnection connection = factory.CreateConnection())
{
using (IModel model = connection.CreateModel())
{
string exchangeName = "customer_update_queue_error";
string queueName = "customer_update_queue_error";
string routingKey = "";
model.ExchangeDeclare(exchangeName, ExchangeType.Fanout);
model.QueueDeclare(queueName, false, false, false, null);
model.QueueBind(queueName, exchangeName, routingKey);
}
}
The send part is to send it directly to the message queue if it fails an x amount of times like so.
consumeContext.Send(new Uri("rabbitmq://localhost/customer_update_queue_error"), consumeContext.Message);
Hopefully the batch feature will be implemented soon and I can use that instead.
https://github.com/MassTransit/MassTransit/issues/800