Purely functional feedback suppression? - functional-programming

I have a problem that I can solve reasonably easy with classic imperative programming using state: I'm writing a co-browsing app that shares URL's between several nodes. The program has a module for communication that I call link and for browser handling that I call browser. Now when a URL arrives in link i use the browser module to tell the
actual web browser to start loading the URL.
The actual browser will trigger the navigation detection that the incoming URL has started to load, and hence will immediately be presented as a candidate for sending to the other side. That must be avoided, since it would create an infinite loop of link-following to the same URL, along the line of the following (very conceptualized) pseudo-code (it's Javascript, but please consider that a somewhat irrelevant implementation detail):
actualWebBrowser.urlListen.gotURL(function(url) {
// Browser delivered an URL
browser.process(url);
});
link.receivedAnURL(function(url) {
actualWebBrowser.loadURL(url); // will eventually trigger above listener
});
What I did first wast to store every incoming URL in browser and simply eat the URL immediately when it arrives, then remove it from a 'received' list in browser, along the lines of this:
browser.recents = {} // <--- mutable state
browser.recentsExpiry = 40000;
browser.doSend = function(url) {
now = (new Date).getTime();
link.sendURL(url); // <-- URL goes out on the network
// Side-effect, mutating module state, clumsy clean up mechanism :(
browser.recents[url] = now;
setTimeout(function() { delete browser.recents[url] }, browser.recentsExpiry);
return true;
}
browser.process = function(url) {
if(/* sanity checks on `url`*/) {
now = (new Date).getTime();
var duplicate = browser.recents[url];
if(! duplicate) return browser.doSend(url);
if((now - duplicate_t) > browser.recentsExpiry) {
return browser.doSend(url);
}
return false;
}
}
It works but I'm a bit disappointed by my solution because of my habitual use of mutable state in browser. Is there a "Better Way (tm)" using immutable data structures/functional programming or the like for a situation like this?

A more functional approach to handling long-lived state is to use it as a parameter to a recursive function, and have one execution of the function responsible for handling a single "action" of some kind, then calling itself again with the new state.
F#'s MailboxProcessor is one example of this kind of approach. However it does depend on having the processing happen on an independent thread which isn't the same as the event-driven style of your code.
As you identify, the setTimeout in your code complicates the state management. One way you could simplify this out is to instead have browser.process filter out any timed-out URLs before it does anything else. That would also eliminate the need for the extra timeout check on the specific URL it is processing.
Even if you can't eliminate mutable state from your code entirely, you should think carefully about the scope and lifetime of that state.
For example might you want multiple independent browsers? If so you should think about how the recents set can be encapsulated to just belong to a single browser, so that you don't get collisions. Even if you don't need multiple ones for your actual application, this might help testability.
There are various ways you might keep the state private to a specific browser, depending in part on what features the language has available. For example in a language with objects a natural way would be to make it a private member of a browser object.

Related

Any way to programmatically open a collapsed console group?

I use console.groupCollapsed() to hide functions I don't generally need to review, but may occasionally want to dig into. One downside of this is that if I use console.warn or console.error inside that collapsed group, I may not notice it or it may be very hard to find. So when I encounter an error, I would like to force the collapsed group open to make it easy to spot the warning/error.
Is there any way to use JS to force the current console group (or just all blindly) to open?
Some way to jump directly to warnings/errors in Chrome debugger? Filtering just to warnings/errors does not work, as they remain hidden inside collapsed groups.
Or perhaps some way to force Chrome debugger to open all groups at once? <alt/option>-clicking an object shows all levels inside it, but there does not appear to be a similar command to open all groups in the console. This would be a simple and probably ideal solution.
There is no way to do this currently, nor am I aware of any plans to introduce such functionality, mainly because I don't think enough developers are actively using the feature to enough of a degree to create demand for this.
You can achieve what you're trying to do, but you need to write your own logging library. First thing you'll need to do is override the console API. Here is an example of what I do:
const consoleInterceptorKeysStack: string[][] = [];
export function getCurrentlyInterceptedConsoleKeys () { return lastElement(consoleInterceptorKeysStack); }
export function interceptConsole (keys: string[] = ['trace', 'debug', 'log', 'info', 'warn', 'error']) {
consoleInterceptorKeysStack.push(keys);
const backup: any = {};
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
const _log = console[key];
backup[key] = _log;
console[key] = (...args: any[]) => {
const frame = getCurrentLogFrame();
if (isUndefined(frame)) return _log(...args);
frame.children.push({ type: 'console', key, args });
frame.hasLogs = true;
frame.expand = true;
_log(...args);
};
}
return function restoreConsole () {
consoleInterceptorKeysStack.pop();
for (const key in backup) {
console[key] = backup[key];
}
};
}
You'll notice a reference to a function getCurrentLogFrame(). Your logging framework will require the use of a global array that represents an execution stack. When you make a call, push details of the call onto the stack. When you leave the call, pop the stack. As you can see, when logging to the console, I'm not immediately writing the logs to the console. Instead, I'm storing them in the stack I'm maintaining. Elsewhere in the framework, when I enter and leave calls, I'm augmenting the existing stack frames with references to stack frames for child calls that were made before I pop the child frame from the stack.
By the time the entire execution stack finishes, I've captured a complete log of everything that was called, who called it, what the return value was (if any), and so on. And at that time, I can then pass the root stack frame to a function that prints the entire stack out to the console, now with the full benefit of hindsight on every call that was made, allowing me to decide what the logs should actually look like. If deeper in the stack there was (for example) a console.debug statement or an error thrown, I can choose to use console.group instead of console.groupCollapsed. If there was a return value, I could print that as a tail argument of the console.group statement. The possibilities are fairly extensive. Here's a screenshot of what my console logs look like:
Note that you will have to architect your application in a way that allows for logging to be deeply integrated into your code, otherwise your code will get very messy. I use a visitor pattern for this. I have a suite of standard interface types that do almost everything of significance in my system's architecture. Each interface method includes a visitor object, which has properties and methods for every interface type in use in my system. Rather than calling interface methods directly, I use the visitor to do it. I have a standard visitor implementation that simply forwards calls to interface methods directly (i.e. the visitor doesn't do anything much on its own), but I then have a subclassed visitor type that references my logging framework internally. For every call, it tells the logging framework that we're entering a new execution frame. It then calls the default visitor internally to make the actual call, and when the call returns, the visitor tells the logging framework to exit the current call (i.e. to pop the stack and finalize any references to child calls, etc.). By having different visitor types, it means you can use your slow, expensive, logging visitor in development, and your fast, forwarding-only, default visitor in production.

meteor: how to stop asynchronous call?

Is it possible to stop (kill) asynchronous Call?
In my app I have at client side sth like:
Meteor.call('doCalculation', function(err, result) {
//do sth with result
});
'doCalculation' may take long time (this is ok) I dont want user to start new call when he/she has already one running call, I want to allow user to stop current call and submit new one. How correctly do this?
The only idea I have is to communicate between client and server using mongo. In some place in 'doCalculation' function I can observe some mongo document/collection and based on this do sth in the function (e.g. call exception). Do you have any better ideas?
You can use a semaphore for this purpose. When the semaphore is 1, requests are allowed to be sent. When the semaphore is 0, requests are not allowed to be sent. The semaphore should be 1 by default and just before you send the request, you need to set it to 0. When a response is successful, you set the semaphore back to 1.
As about the timeout: You could use a time out using setTimeout after sending the request, like this:
if (semaphore) {
var isTimedOut = false;
var isSuccess = false;
semaphore = 0; //No need to use var keyword, as this should be declared outside of this scope
Meteor.call('doCalculation', function(err, result) {
isSuccess = true;
//do sth with result
});
setTimeout(function() {
if (!isSuccess) {
isTimeout = true;
//do something else, to handle the time out state
}
}, 10000);
}
This is tricky, because you cannot generally set timeouts from the client's point of view. You don't need to, for a bunch of architectural reasons. The most important thing is that if you lose network connectivity or the server crashes (two cases timeouts are designed to manage), the client is aware immediately because it is disconnected. You can use Meteor.status().connected if this happens often.
It sounds like you're running a long calculation on the server. My suggestion is to return a calculationId immediately, and then update a collection with progress, e.g., CalculationProgresses.update(calculationId, {$set: {progress: currentProgress}}) as you calculate. Your UI can then update the progress reactively, in the most convenient way possible.
Note, that when you do run long calculations on the server, you need to occasionally "yield," giving the chance for other work to happen. Node, on which Meteor is based, is tricky for long calculations if you don't master this notion of yielding. In Meteor, you can yield easily by updating a collection (e.g., your progress collection). This will solve lots of problems you're probably experiencing as you write your application.
i think you need a server-side solution for this. if you go with a client-side solution, you don't handle 2 cases:
the user reloads their browser
the user uses 2 browsers
i would create these methods:
isCalculationActive() -- this checks if the user already has a calculation active. on the server, you can either keep that fact in memory or write it to the db. on the client, if this returns false, then you can proceed to call doCalculation(). if true, you can give the user a popup or alert or something to ask if they want to cancel and proceed.
doCalculation() -- this cancels any outstanding calculation by that user and starts a new one.
with these implemented, the user can reload their browser w/o affecting either the running calculation or correct behavior. and if they try a 2nd browser, everything should still work as expected.
if you want to give the user the option to simply stop the job and not start a new one, then you can simply create:
cancelCalculation() -- this cancels any outstanding calculation by that user.

How can I use collection.find as a result of a meteor method?

I'm trying to follow the "Use the return value of a Meteor method in a template helper" pattern outlined here, except with collections.
Essentially, I've got something like this going:
(server side)
Meteor.methods({
queryTest: function(selector) {
console.log("In server meteor method...");
return MyCollection.find(selector);
}
});
(client side)
Meteor.call('queryTest', {}, function(error, results) {
console.log("in queryTest client callback...");
queryResult = [];
results.forEach(function(result) {
// massage it into something more useful for display
// and append it to queryResult...
});
Session.set("query-result", queryResult);
});
Template.query_test_template.helpers({
query_test_result: function() {
return Session.get("query-result");
}
});
The problem is, my callback (from Meteor.call) doesn't even get invoked.
If I replace the Method with just 'return "foo"' then the callback does get called. Also, if I add a ".fetch()" to the find, it also displays fine (but is no longer reactive, which breaks everything else).
What gives? Why is the callback not being invoked? I feel like I'm really close and just need the right incantation...
If it at all matters: I was doing all the queries on the client side just fine, but want to experiment with the likes of _ensureIndex and do full text searches, which from what I can tell, are basically only available through server-side method calls (and not in mini-mongo on the client).
EDIT
Ok, so I migrated things publish/subscribe, and overall they're working, but when I try to make it so a session value is the selector, it's not working right. Might be a matter of where I put the "subscribe".
So, I have a publish that takes a parameter "selector" (the intent is to pass in mongo selectors).
On the client, I have subscribe like:
Meteor.subscribe('my-collection-query', Session.get("my-collection-query-filter"));
But it has spotty behaviour. On one article, it recommended putting these on Templates.body.onCreate. That works, but doesn't result in something reactive (i.e. when I change that session value on the console, it doesn't change the displayed value).
So, if I follow the advice on another article, it puts the subscribe right in the relevant helper function of the template that calls on that collection. That works great, but if I have MULTIPLE templates calling into that collection, I have to add the subscribe to every single one of them for it to work.
Neither of these seems like the right thing. I think of "subscribing" as "laying down the pipes and just leaving them there to work", but that may be wrong.
I'll keep reading into the docs. Maybe somewhere, the scope of a subscription is properly explained.
You need to publish your data and subscribe to it in your client.
If you did not remove "autopublish" yet, all what you have will automatically be published. So when you query a collection on client (in a helper method for example), you would get results. This package is useful just for quick development and prototyping, but in a real application it should be removed. You should publish your data according to your app's needs and use cases. (Not all users have to see all data in all use cases)

Iron router + observechanges = repeated observechanges handler calls?

I'm attempting to use observechanges with iron router but they don't seem to be compatible at all.
Router.route('/gaming', {
waitOn: function() {
return Meteor.subscribe('chat', function() {
window.chatmessagesCache = new ReactiveVar;
chatmessagesCache.set([]);
return chat.find().observeChanges({
added: function(id, doc) {
var tmpArr;
tmpArr = chatmessagesCache.get();
tmpArr.push(doc);
return chatmessagesCache.set(tmpArr);
}
});
});
}
If I leave the route and come back to it, observechanges begins being handled as many times as I've navigated away and returned, for each new record. What's the deal?
If I use subs manager it works as expected, but I don't understand why Meteor.subscribe inside waitOn is so cache/subscription unaware when it ALREADY gets called multiple times per load. Why!? I can't decipher what's causing this behavior at all.
Also, what I'm trying to accomplish is simple. I want to let chat messages that the user's client has received remain on the page even if the chat cursor is no longer publishing them (I'm publishing the last 10 chat messages)
Iron router has reactivity built in, which means when something inside your route function is invalidated, it will repeat the function as well as anything reactive with a Router.current(). These unexpected invalidation runs are a primary reason why folks made the exodus to flow router.
To solve this, you'll want to abstract your code away from the router. You can leave the sub, but I'd suggest you remove the sub's callback from the waitOn and move it into an onRendered callback. If you don't want the history loaded in chunks, you can first do a var collectionCount = chat.find({},{reactive:false}).count() on how many docs are in the collection & then in the added callback you can do something like if (++currentCount === collectionCount) /* add stuff */ to add al the records to the history when it reaches the last record.
On a bigger picture level, consider eliminating the observeChanges & just do an #each over the chat collection in spacebars to show your messages. Fewer cycles, cleaner code.
Iron router just has no management of observations you created yet it manages subscriptions itself, hence the multiple additions.
I figured this out by using a window level variable to check if I'm observing. Even in cases when the subscription is unhooked by iron, if I go back and never re-add the handler, the original observation hook still runs (!). ALSO, if you navigate away and drop the subscription, the handler is no longer called--which is the behavior I want in this scenario (This is all very insane behavior but at least it's now predictable to me )
This is caused by the fact that subscriptions != collections and the API for observations doesn't seem to expose any metadata, unfortunately, so I don't know how the iron router maintainers would account for this. Not to mention you return iron router a subscription, not a collection.
#Matt K if you were correct, this would always be an infinite loop (which admittedly I had a bunch of while trying to solve this) but the posted code is adding too many handlers, not looping indefinitely. Thanks for the post though.
This is what I settled on
Router.route('/gaming',
waitOn: ->
Meteor.subscribe('chat', ->
window.chatmessagesCache = new ReactiveVar(chat.find().fetch().reverse())
if !window.chatListening
window.chatListening = true
after = chat.find().count()
chat.find().observe(
added: _.after(after + 1,(doc) ->
tmpArr = chatmessagesCache.get()
tmpArr.push(doc)
chatmessagesCache.set(tmpArr))
changed : (id, doc) ->
))
I really just wanted to test out a pattern of locally "disconnected" documents. I still may use subs manager because it keeps subscriptions and their handlers alive without rerunning them constantly (which was rerunning the sub handler, which was adding multiple observations)

Design suggestion needed to convert synchronous qtdbus calls to asynchronous

The applications in my project were until now communicating over qtdbus using synchronous calls. However I now need to convert a few of these calls to asynchronous.
For that I chose to use this API available in qtdbus
QDBusAbstractInterface::callWithCallback
But the problem is that the current implementation has these qtdbus sync calls scattered in a lot of places in the code and the code snippets which follow these sync calls assume that the control only reaches them when the preceding call has been successfully serviced and a reply is obtained.
This will no longer be the case when the calls change to async. Moreover the calls are made in different contexts, so I will be required to maintain the state of the system before each qtdbus call, so that I know what to do when I receive the reply.
Is there any chance really to somehow convert the calls to async without rupturing the fabric of the current code in a big way?
One approach I can think of is to use the FSM pattern.
Any hints or design suggestions will be much appreciated.
Thanks!
The way I am understanding is that you will need to call the same method and then process the return value differently based on the state at the time of the call. Such as
void function()
{
//do stuff
value = SynchronousCall();
if (state == 1)
{
doSomething(value);
}
else
{
doSomethingElse(value);
}
}
I would recommend instead of a full implementation of the Finite State Machine pattern which can make a mess with the number of classes that it adds, add separate methods for each state
void function()
{
//do stuff
if (state == 1)
{
callback = *doSomething(ValueType);
}
else
{
callback = *doSomethingElse(ValueType);
}
callWithCallback(method,args, receiver,callback,error);
}
Then in each method you can assume the state and process the return value accordingly.
Another slightly (very) hacky way would be to simply have a spin wait after all the asynchronous calls and use a QThread:: yield() in the loop while you wait for the value to return. That way it is still technically an asynchronous call but it acts synchronous.

Resources