Weird Angular exception: [$rootScope:inprog] null already in progress - angularjs

I get a very strange exception with AngularJS 1.5.9
[$rootScope:inprog] null already in progress
Here is the source code where this exception is thrown:
function beginPhase(phase) {
if ($rootScope.$$phase) {
throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
}
$rootScope.$$phase = phase;
}
beginPhase() is called with "$apply" or "$digest".
My question is:
How is it possible to enter the "if" while $rootScope.$$phase is null?
Any help will be appreciated.

To answer your question $rootScope.$$phase can be set to "null" (string) which will result in this error being thrown.
I'm not sure how you were able to capture this message but Sentry reports that for me and I'm getting a ton of those exceptions from just a bunch of users.
So in order to reduce the spam I made a function which will remove the stack from the exception, and will clear the $rootScope.$$phase which will hopefully prevent a second occurrence:
function exceptionHandler(){
const error = Error;
const nullMessage = "[$rootScope:inprog] null already in progress";
function exception(message){
if(message.indexOf(nullMessage) === 0){
const $rootScope = exceptionHandler.$rootScope;
if($rootScope) $rootScope.$$phase = null;
const exception = new error(nullMessage);
exception.stack = "";
return exception;
}
return new error(message);
}
Error = exception;
}
exceptionHandler(); // If it's not run AngularJS will use the original Error constructor, the one we're decorating
And then in angular.run inject $rootScope and set it as a property of the function:
angular.run(["$rootScope", function($rootScope){
exceptionHandler.$rootScope = $rootScope;
}]);
My assumption was that an extension was setting $rootScope.$$phase to "null" but after installing the same extensions as one of my users the exception did not occur.
Star on GistHub

Related

How to interrupt JoinPoint execution in AOP

Is it possible to interrupt invoking the actual method from within the aspect execution?
For example:
public class CheckPermissionAspect {
#Around("#annotation(CheckPermission)")
public Object methodLogging( ProceedingJoinPoint joinPoint) throws Throwable {
// before method execution
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
log.info("Enter ==> " + signature.getMethod().getName());
if ( getPermission( principal.getName()) == false ) {
// break the execution of actual method
Object result = null; // ???
log.info("Break ==> " + signature.getMethod().getName());
} else {
// invoke the actual method
Object result = joinPoint.proceed();
// after method execution
log.debug("Result: " + result);
log.info("Leave ==> " + signature.getMethod().getName());
}
return result;
}
}
To set Object result = null; does not work.
Thank you for any help.
From Spring Reference documentation : Around Advice
Within the body of the advice method, you must invoke proceed() on the
ProceedingJoinPoint in order for the underlying method to run
If joinPoint.proceed() is removed from the code or an exception is thrown before joinPoint.proceed() statement or a return is issued before joinPoint.proceed() statement , the execution of the underlying method would get interrupted.
Update : to answer the comment
Spring AOP is proxy based. To understand this concept better , do read through : Understanding AOP proxies
An advice is placed between the calling method and the target. All calls to the target method gets intercepted and advised.
You could throw an exception upon validation ( Do note that the exception type thrown should match the exception type of the target method . Go through this Q&A).
The exception/return value from the advise would reach back the calling method .

Is it possible to selectively ignore service exception in Hystrix?

I have client API jar which internally makes external calls and throws single generic Service exception in case of issues. I have written hystrix wrapper over the API calls. There are cases like "user not found" returning exception. Though the call was successful and service responded with valid response, the hystrix is treating it as a failure. I know that we can ignore the exception in Hystrix; but it will whitelist the only exception thrown by service calls. Is there a way to selectively ignore exception thrown by the service calls based on message in exception or http status code or something?
If the external service throw different exceptions in different cases, then you can probably ignore those exceptions like this
#HystrixCommand(ignoreExceptions = {SomeException.class})
But if you have to ignore exceptions bases on error message then the best way to tackle this is put a try catch around your external call. And in the catch block check if it is one of those exceptions which needs to be ignored. If so don't do anything. If not rethrow this exception. Something like this will do. More info about HystrixBadRequestException
#HystrixCommand(fallbackMethod = "fallBackMethod", groupKey = "CircuitBreaker", commandKey = "somekey", threadPoolKey = "somekey",
commandProperties = {
#HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "10000"),
#HystrixProperty(name = "execution.timeout.enabled", value = "false"),
#HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
#HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "1200000"),
},
threadPoolProperties = {
#HystrixProperty(name = "coreSize", value = "30"),
#HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "180000")
})
public void someMethod(....){
try {
// Call external service
} catch(Exception e) {
if(exception to be ignored)
throw new HystrixBadRequestException("Some message", e);
else
throw e
}
}

change tracking in manager after saveChanges BreezeJs

I'm using Breeze and Angular on client and NHibernate on server.For business logic reasons I need to know if some object has changes after it has been saved.For that reasons I'm calling
manager.hasChanges(['ArrayOfTypes']);
In case when object is loaded from db it works as expected(returns true/false),
but after object is saved through
manager.saveChanges(['ArrayOfTypes']);
I get this error:
TypeError: Cannot read property 'hasChanges' of undefined
The error gets thrown here in breeze.js file:
proto._hasChangesCore = function(entityTypes) {
entityTypes = checkEntityTypes(this, entityTypes);
var entityGroups = getEntityGroups(this, entityTypes);
return entityGroups.some(function (eg) {
return eg.hasChanges();
});
};
I'm expecting 32 entityGroups to return and there are indeed 32 elements in array, but 25 of them are undefined.For now I've made a temp fix which does not feel right at all:
proto._hasChangesCore = function(entityTypes) {
entityTypes = checkEntityTypes(this, entityTypes);
var entityGroups = getEntityGroups(this, entityTypes);
return entityGroups.some(function (eg) {
if (eg !== undefined) {
return eg.hasChanges();
}
else {
return false;
}
});
};
Is there a way to deal with problem in other way?
Thanks
This happens when the one or more of the entity types is not represented by an EntityGroup in the entity manager. But you should be able to pass in any type name and not have it blow up.
This is a bug in Breeze, which is finally fixed. The fix will be in the next release.

How to get the status of angular $interval - check if the interval has been cancelled or not

I am new to Angular (and JS) and just a little confused.
I start a timer with :
var getOverviewMapTimer = $interval($scope.UpdateOverviewMap, UPDATE_FREQUENCY);
and, if I understand it, getOverviewMapTimer is a "promise".
I want to be able to check if the timer is running & had excepted that if I ever
$interval.cancel(getOverviewMapTimer); then getOverviewMapTimer would be null and I could check for that.
This seems not to be the case.
Do I have to explicitly destroy the promise (what goo is a promise to timer that has been cancelled?).? If so, how & would I then have to explicitly set it to null?
I think that I should use cancel(getOverviewMapTimer);, but am not 100% sure as getOverviewMapTimer is still non-null afterwards.
Thanks for your help
After var getOverviewMapTimer = $interval(...); getOverviewMapTimer holds a reference to an object (that happens to be a promise).
Doing $interval.cancel(getOverviewMapTimer) passes (and cancels) the object referenced by the getOverviewMapTimer variable, but there is no way to convert an object to null. The getOverviewMapTimer variable will continue to hold a reference to the promise object and the only way to set it to null is through a new assignment (i.e. explicitely setting it to null):
var getOverviewMapTimer = $interval(...);
...
$interval.cancel(getOverviewMapTimer);
getOverviewMapTimer = null;
Advanced Topic:
It sounds indeed nice to have an easy way to find out if an interval-promise has been cancelled or not (e.g. adding a custom cancelled property to the promise object and setting its value to true when cancelling the interval).
Angular is cool enough to be incredibly flexible and extensible, so using the concept of a Service Decorator we are able to "augment" the $interval service, extending its cancel() method to add a cancelled property and setting its value to true when cancelling an interval-promise:
/* Service Decorators can be configured in `config` blocks */
app.config(function ($provide) {
/* Register a decorator for the `$interval` service */
$provide.decorator('$interval', function ($delegate) {
/* Keep a reference to the original `cancel()` method */
var originalCancel = $delegate.cancel;
/* Define a new `cancel()` method */
$delegate.cancel = function (intervalPromise) {
/* First, call the original `cancel()` method */
var retValue = originalCancel(intervalPromise);
/* If the promise has been successfully cancelled,
* add a `cancelled` property (with value `true`) */
if (retValue && intervalPromise) {
intervalPromise.cancelled = true;
}
/* Return the value returned by the original method */
return retValue;
};
/* Return the original (but "augmented") service */
return $delegate;
});
});
Now, we can use the $interval service as usual and we can always check an interval-promise's cancelled property to find out if it has been cancelled.
var getOverviewMapTimer = $interval(...);
...
console.log(!!getOverviewMapTimer.cancelled); // false
$interval.cancel(getOverviewMapTimer);
console.log(!!getOverviewMapTimer.cancelled); // true
See, also, this short demo.
It's technically impossible that getOverviewMapTimer is null after calling $interval.cancel(getOverviewMapTimer);.
If you want it to be null you have to do it yourself. Either immediately after cancelling the interval or via callback:
if ($interval.cancel(getOverviewMapTimer)) {
getOverviewMapTimer = null;
}
or
var getOverviewMapTimer = $interval($scope.UpdateOverviewMap, UPDATE_FREQUENCY);
getOverviewMapTimer.catch(function() { getOverviewMapTimer = null; });
Be aware, though, that the callback is asynchronous.
easy
var interval = $interval(function() { }, 1000);
console.log(interval.$$state.status); //0
$interval.cancel(interval);
console.log(interval.$$state.status); //2
if(interval.$$state.status == 0)
//valid
else
//invalid

"Cannot read property 'transport' of undefined " in karma-jasmine Unit Test

I built a project with AngularJs and made unit test with Karma and jasmine.
One of my controller in Angular project need to refer socket.io to transport data with server. And i wrote the unit test case for this controller. Ana add 'socket.io.js' file into 'karma.conf.js', When i tested it with karma, an error throw out:
Uncaught TypeError: Cannot read property 'transport' of undefined, this error throw in below statement in adapter.js in karma-jasmine node package:
var getCurrentTransport = function() {
// probably running in debug.html (there's no socket.io)
if (!window.parent.io) {
return null;
}
var location = window.parent.location;
return window.parent.io.sockets[location.protocol + '//' + location.host].transport.name;
};
i'm not quit understand what this code mean, i found that the window.parent.io.sockets is an empty object, so added another statement to return null so that it won't throw an error.
var location = window.parent.location;
if(!window.parent.io.sockets[location.protocol + '//' + location.host]){
return null;
}
return window.parent.io.sockets[location.protocol + '//' + location.host].transport.name;
i'm not sure whether this change is right? Anyone know how to fix this problem?
#Zacho add these statement before return... in your adapter.js .
if(!window.parent.io.sockets[location.protocol + '//' + location.host]){
return null;
}
these just hack method,Although I don't think this is a good solution, i didn't find why this problem occur.

Resources