In my chat client application, I have a Subject which gets OnNext-ed when a connection to the server drops OR a connection attempt fails. There is a subscription that when gets notified makes an attempt at a connection.
The way my chat application is and the way server connection works it sometimes allows multiple notifications around the same time, meaning while the subscription is processing one Job, it gets another in the queue which NEEDS TO BE IGNORED.
I am using an external local thread-safe variable to let my subscription know if it should ignore any other notifications.
reconnectSubject
.Where(x => this.IsRetryInProcess == false)
.Select(x =>
{
this.SetRetryInProcessThreadSafe(true);
var result = MakeConnectionAttemptAndReturnResult();
this.SetRetryInProcessThreadSafe(false);
return result;
)
.Where(x => x.IsSuccessful == false)
.Subscribe(x => reconnectSubject.OnNext(Unit.Default));
This works but it lacks keeping things coherent or encapsulation. I have mixed together the two worlds there. Is there any Operator in Observable that can help me achieve this without a external flag? May be some sort of an observable that requires ACKs?
Related
Working with Firebase in a Unity project, for a simple highscore, I stumbled on problems when doing a query.
In editor, everything works like a charm (Editor does not have persistence)
On devices (with persistence enabled) the troubles begin. Query is showing cached Firebase data, so it is only correct on first ever call in the client, and then when Firebase sees it fit to sync (maybe never, since there is no eventhandler)
However, looking for a solution, there is no way to force an update of the cached values.
I then tested with KeepSynced(true) on the query and this seems to work:
this.HiscoreQuery = hiscoreref.OrderByChild ("Score").LimitToLast (20);
this.HiscoreQuery.KeepSynced(true);
this.HiscoreQuery.GetValueAsync().ContinueWith (task => {
if (task.IsFaulted) {
Debug.LogError ("Get hiscores faulted");
return;
}
if (task.Result != null && task.Result.ChildrenCount > 0) {
Debug.Log ("Get hiscore data success!");
this.AddDelayedUpdateAction (() => this.OnGetHiScores (task.Result));
}
});
Question: While this can be fine if Firebase only listen for the Query's LImitToLast(20), it would be a very bad thing, if the Firebase internally is keeping the whole (growing) hiscorelist copied in every client.
Does anyone know if KeepSynced(true) is limited to the actual query scope or the whole tree/branch? And how could one validate this?
GetValue calls don't work well with KeepSynced(true). Firebase eagerly returns you the value from the cache, and only then loads the data from the server.
For a longer explanation, see my answer here: Firebase Offline Capabilities and addListenerForSingleValueEvent
If you want to use caching, use listeners and not GetValue calls. With a listener, your callback will be fired twice (if there is a change): once with the value from the cache, and then once with the value from the server.
I have a situation where I am running an interactive C# console-program from node/express. The program runs in an infinite loop, accepts a string from the command-line, and echoes it back.
The following code works for the first time I call http://localhost:3000?command=hello
Next time around, Node crashes by reporting Can't set headers after they are sent.
If the move the const script = spawn('/Users/amarshanand/shadowClient/myscript.sh'); in the sendToShell(), it works, but since I have to start a new shell and the script, it takes a lot longer.
How can I make it work like start once and accept command for each request.
const express = require('express')
const app = express()
const { spawn } = require('child_process');
const script = spawn('/Users/amarshanand/shadowClient/myscript.sh');
const sendToShell = (command, done) => {
script.stdout.on('data', (stdout) => {
console.log(`stdout: ${stdout}`);
done(stdout);
});
script.stderr.on('data', (stderr) => {
console.log(`error: ${stderr}`);
});
script.stdin.write(`${command}\n`);
}
app.get('/', (req, res) => {
sendToShell(req.query.command, result => res.send(`${result}`));
})
app.get('/getstate', (req, res) => {
res.send('state');
})
app.post('/setstate:state', (req, res) => res.send('posted state'));
app.listen(3000, () => console.log('Example app listening on port 3000!'))
That particular error occurs when you try to send more than one response to an incoming request. When I examine your code, I see that this particular piece of code:
script.stdout.on('data', (stdout) => {
console.log(`stdout: ${stdout}`);
done(stdout);
});
Can receive the data event more than once and when it does, it will call done(stdout) more than once which will cause the caller to call res.send() more than once.
With streams, you have no idea how many times the data event will be called. It could be called only once or it could be called many times with lots of small pieces of data.
In addition, you only have one script that all your requests use. So, each time you call sendToShell(), you add yet another script.stdout.on('data', ...) event handler so they will pile up and you will have duplicates causing you to call done() more than once for each data event. If you're going to stick with this structure, then you need a way to know when all the data has been sent for the last command and then you need to remove that event handler so they don't pile up.
FYI, this code also has concurrency issues because multiple requests could come into your server that cause you to run a command and you'd have no idea which response belongs with which command. If you're going to keep just one shell open, they you probably need to queue commands to the shell so you don't send the next command or set up its event handlers to read the response until the previous command is done. That way you won't be reading the response from the wrong command.
I have designed one application (C# with .net 4.5) which connects to multiple Ethernet enabled hardware devices(Maximum 100 Devices) for data transfer purpose using request response mechanism.
Each hardware device has unique ip address and port configured, my application using tcpclient class connects and communicates with this devices.
Now my requirement is,
Make application multi-threaded so that it will be able to connect all the devices at the same time. (Thread per connection)
The communication which happens with all this devices is repetitive i.e. after every specific interval it should connect to all devices for data transfer purpose on 24X7 basis.
I have one more additional requirement to this is, the interval should be configured once function (callback function) finish the execution. Because some time device delayed the response so I cannot make the use of sleep, delay or equivalent functionality. In this case new iteration may start even if the last iteration was not completed which I want to prevent.
i.e. if I connect to device data transfer should happen and only after that it should set the interval for next execution.(Most probably in callback function itself)
To achieve this I am thinking to make the use threading.timer, for this I can set the thread interval in callback function itself. I am testing this and seems working initially and I believe I can further optimize this code to work in production environment.
But doing further Google I started believing that task parallel library is more efficient and since I am working on .net 4.5 I should make the use of this rather than classical threading.timer class.
But since TPL doesn’t have exact equivalent as threading.timer I will have to work on it to make perfect fit for my requirement.
So my question if i make the use of TPL with some customization rather than threading.timer will I really get any performance gain or should i continue with threading.timer only.
I would suggest using Microsoft's Reactive Framework (NuGet "System.Reactive") for this over both threads and TPL. Here's what I'd do:
Start by defining an array of TimeSpan values that can be used to change the scheduling of each device:
int devices = 3;
TimeSpan[] timerTimeSpans =
Enumerable
.Range(0, devices)
.Select(x => TimeSpan.FromMilliseconds(2000))
.ToArray();
I've started with a default of 2000 ms.
Then define a method to read from the devices:
public Task<DeviceResult> DeviceFetchAsync(int device_number, Action<TimeSpan> reschedule)
{
if (device_number == 1)
{
reschedule(TimeSpan.FromMilliseconds(10000));
}
return Task.Factory.StartNew(() => new DeviceResult()
{
DeviceNumber = device_number
});
}
public class DeviceResult
{
public int DeviceNumber;
}
It includes an Action<TimeSpan> reschedule to change the scheduling for this particular device.
Now for the Rx query that sets up all of the timers and reads from the devices:
IObservable<DeviceResult> query =
Observable
.Range(0, devices)
.Select(n =>
Observable
.Generate(0, x => true, x => x + 1, x => x, x => timerTimeSpans[n])
.SelectMany(x =>
Observable
.FromAsync(() => DeviceFetchAsync(n, ts => timerTimeSpans[n] = ts))))
.Merge();
And finally the subscription that sets the whole thing off:
IDisposable subscription =
query
.Subscribe(r => Console.WriteLine(r.DeviceNumber));
If you want to stop everything, just do subscription.Dispose();.
That's it. That's all the code. I've tested this and it works fine.
I'm struggling with a ReactiveUI use case that I feel is so simple there must be "out-of-the-box" support for it. But I cannot find it.
The scenario is a basic search interface with these features:
A search string TextBox where the user enters the search text
A result TextBox where the result is presented
An indicator showing that a search is in progress
The search should work like this:
The search string TextBox is throttled, so that after 500ms of
inactivity, a search operation is initiated.
Each time a new search is initiated any ongoing search operation should be cancelled.
Basically I'm trying to extend the "Compelling example" to cancel the currently executing command before starting a new command.
Seems easy enough? Yeah, but I cannot get it right using ReactiveCommand. This is what I have:
var searchTrigger = this.WhenAnyValue(vm => vm.SearchString)
.Throttle(TimeSpan.FromMilliseconds(500))
.Publish().RefCount();
var searchCmd = ReactiveCommand.CreateFromObservable(
() => Observable
.StartAsync(ct => CancellableSearch(SearchString, ct))
.TakeUntil(searchTrigger));
searchCmd.ToPropertyEx(this, vm => vm.Result);
searchCmd.IsExecuting.ToPropertyEx(this, vm => vm.IsSearching);
searchTrigger.Subscribe(_ => searchCmd.Execute(Unit.Default).Subscribe());
The above code works in all aspects except searchCmd.IsExecuting. I kick off a new search regardless of the state of searchCmd.CanExecute. This makes IsExecuting unreliable since it assumes serial operation of the commands. And I cannot use InvokeCommand instead of Execute since then new searches would not be started while a search is in progress.
I currently have a working solution without ReactiveCommand. But I have a strong feeling this simple use case should be supported in a straightforward way using ReactiveCommand. What am i missing?
AFAICT Rx7 doesn't really handle this kind of overlapping execution. All the messages will eventually make it through but not in a way that will keep your IsExecuting consistently true. Rx6 used an In flight counter so overlapping executions were handled but Rx7 simplified it all way down. Most likely for performance and reliability (but I'm just guessing). Because Tasks aren't going to cancel right away that first command is going to complete after the second command starts which leads to IsExecuting toggling from true to false to true to false. But that middle transition from false to true to false happens instantly as the messages catch up. I know you said you had a non Reactive Command working but here's a version that I think works with Reactive Commands by waiting for the first command to finish or finish cancelling. One advantage to waiting until the Task actually cancels is that you are assured you don't have two hands in the cookie jar :-) Which might not matter in your case but can be nice in some cases.
//Fires an event right away so search is cancelled faster
var searchEntered = this.WhenAnyValue(vm => vm.SearchString)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Publish()
.RefCount();
ReactiveCommand<string, string> searchCmd = ReactiveCommand.CreateFromObservable<string, string>(
(searchString) => Observable.StartAsync(ct => CancellableSearch(SearchString, ct))
.TakeUntil(searchEntered));
//if triggered wait for IsExecuting to transition back to false before firing command again
var searchTrigger =
searchEntered
.Throttle(TimeSpan.FromMilliseconds(500))
.Select(searchString => searchCmd.IsExecuting.Where(e => !e).Take(1).Select(_ => searchString))
.Publish()
.RefCount();
_IsSearching =
searchCmd.IsExecuting
.ToProperty(this, vm => vm.IsSearching);
searchTrigger
.Switch()
.InvokeCommand(searchCmd);
Not sure about the title of my question but hopefully I can explain what I am trying to do.
I want to have a Timer to inject a value into a sequence but when a specific value is observed.
I want the Timer to be cancelled when any other value is entered into the sequence.
public enum State
{
Connected,
Disconnected,
DisconnectedRetryTimeout
}
var stateSubject = new Subject<State>();
var connectionStream = stateSubject.AsObservable();
var disconnectTimer =
Observable.Return(State.DisconnectedRetryTimeout)
.Delay(TimeSpan.FromSeconds(30))
.Concat(Observable.Never<State>());
var disconnectSignal =
disconnectedTimer
.TakeUntil(connectionStream.Where(s => s == State.Connected))
.Repeat();
var statusObservable =
Observable.Merge(connectionStream, disconnectSignal)
.DistinctUntilChanged();
So when nothing is in the stream (i.e. new) no timer.
When Connected|DisconnectedRetryTimeout is add no timer.
When Disconnected is add I want the timer to start
If Connected is on the stream before the timer fires I want the timer cancelled
The Timer should only fire once, until Disconnected is received again.
Pretty new to RX and ran out of ideas on this one.
Any help much appreciated.
If I understand the problem correctly: We start with a state stream that will emit either Connected or Disconnected messages. We want to enrich this with DisconnectedRetryTimeout message that appears if a Disconnected message sits on the stream for 30 seconds without a Connected message appearing.
One way to do this has the following idea:
Project the Connected/Disconnected stream into the DisconnectedRetryTimeout stream as follows:
First strip duplicates with DistinctUntilChanged as we only want the first Disconnected message of a batch to start a timer.
If Disconnected is received, project this event as a stream that emits DisconnectedRetryTimeout after 30 seconds
If Connected is received, just project an infinite and empty stream (Observable.Never)
With the above, we end up with a stream of streams, so now we use Switch which flattens this by always taking the most recent stream. So if Connect appears whilst the timer is in flight, the Never stream will replace the timer stream.
Now we can merge this with the original de-duped stream. Note that we publish the de-duped stream because we will be subscribing to it twice - if we don't do this, and the source is cold then we can run into problems. See more about that here.
var stateSubject = new Subject<State>();
var state = stateSubject.DistinctUntilChanged().Publish().RefCount();
var disconnectTimer = state
.Select(x => x == State.Disconnected
? Observable.Timer(TimeSpan.FromSeconds(30))
.Select(_ => State.DisconnectedRetryTimeout)
: Observable.Never<State>())
.Switch();
var statusObservable =
state.Merge(disconnectTimer);
EDIT: Simpler Version
You can do this all in one go and drop the publish step and merge - by using StartWith we can push the Disconnected events through the timer stream, and with Observable.Return we can push the Connected through replacing the empty Never stream:
var statusObservable = stateSubject
.DistinctUntilChanged()
.Select(x => x == State.Disconnected
? Observable.Timer(TimeSpan.FromSeconds(5))
.Select(_ => State.DisconnectedRetryTimeout)
.StartWith(State.Disconnected)
: Observable.Return(State.Connected))
.Switch();