I am unsuccessful at catching an sqflite SQL error that throws a database exception. Note: it's a Future and async.
Sample Code
Future<String> getData() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, globals.databaseName);
Database db = await openDatabase(path);
List results = await db.rawQuery("mal formed example of sql on purpose");
}
When I run the code above, rawQuery throws the on-purpose bad SQL. The console shows:
E/SQLiteLog( 7908): (1) near "mal": syntax error
What I want to do is be able to catch SQL errors and handle them.
I've tried .then and .catchError - but not getting it to work.
And from what I've read, normal try {} catch {} doesn't work on Futures. (I did try that to start with... and it didn't work).
try {
List results = await db.rawQuery("mal formed example of sql on purpose");
} catch (e) {
print(e);
}
results in the same error:
E/SQLiteLog( 3148): (1) near "mal": syntax error
Sounds like the issue got fixed by upgrading to the latest version (don't know which version was used in the reported issue): https://github.com/tekartik/sqflite/issues/17
The SQLException (iOS and Android) is propagated to Dart and can be caught as a DatabaseException using try/catch when using async/await, as shown in the test here: https://github.com/tekartik/sqflite/blob/master/example/lib/exception_test_page.dart#L89-L94
Related
I have some code like this:
File("foo.txt").readAsString().catchError((e)=>print(e));
The compiler is complaining
info: The return type 'void' isn't assignable to 'FutureOr<T>', as required by 'Future.catchError'.
I can't seem to give it what it wants and can't find a single clear usage example in any of the docs (just a long issue in git about how many ways there are to mis-use this). If I take the docs at face value, I should be able to return a bool, or a future, neither make the analyzer happy.
How do I provide this FutureOr?
The documentation for Future.catchError could be a lot clearer, but the relevant part is:
onError is called with the error and possibly stack trace, and the returned future is completed with the result of this call in exactly the same way as for then's onError.
Cross-referencing to the documentation for Future.then, the relevant portion is:
The onError callback must return a value or future that can be used to complete the returned future, so it must be something assignable to FutureOr<R>.
Since File.readAsString returns a Future<String>, your catchError callback also must return a Future<String>. Examples of doing that:
File("foo.txt").readAsString().catchError((e) {
print(e);
return Future.value('');
});
File("foo.txt").readAsString().catchError((e) async {
print(e);
return '';
});
Logically, this makes sense; because given:
String value = await File("foo.txt").readAsString().catchError(...);
then if readAsString succeeds, value should be assigned a String. If it fails, since you catch the exception without rethrowing it, value still needs to be assigned a String.
Put another way, your code is equivalent to:
Future<String> readFoo() async {
try {
return await File("foo.txt").readAsString();
} catch (e) {
print(e);
}
// Oops, missing return value.
}
In general, I strongly recommend using async/await with try-catch instead of using .catchError, which would avoid this confusion.
When I tried to use ResilienceDecorator.executeCallable() to enable circuit breaker, I have to throw out ResilienceRuntimeException in my callable to make the circuit break work. Sample code as below. Without it, circuit breaker is always closed. is this the right way to do it?
response = ResilienceDecorator.executeCallable(() -> {
HttpResponse response1 = tryHttpClient.get().execute(request);
if (response1.getStatusLine().getStatusCode() == 404){
throw new ResilienceRuntimeException("404 error is raised when calling SB api");
}
return response1;
},
ResilienceConfiguration.of(SubscriptionBillingAdapter.class).isolationMode(ResilienceIsolationMode.TENANT_OPTIONAL).timeLimiterConfiguration(ResilienceConfiguration.TimeLimiterConfiguration.of().timeoutDuration(Duration.ofSeconds(6L))).circuitBreakerConfiguration(ResilienceConfiguration.CircuitBreakerConfiguration.of().waitDuration(Duration.ofSeconds(600000L)).failureRateThreshold(1).closedBufferSize(1).halfOpenBufferSize(1)),
e -> {LOG.warn("resiliience fallback call: " + e); return response1;});
I am asking since I don't see any document of it. Also when I check how destination configuration in SCP is retrieved, I saw the following code in com.sap.cloud.sdk.cloudplatform.connectivity.DestinationService . It doesn't throw out ResilienceRuntimeException, when using ResilienceDecorator.executeCallable(). so my question is do I need to throw out ResilienceRuntimeException or not to make circuit breaker work? if I don't need, anything wrong in my code?
return (String)ResilienceDecorator.executeCallable(() -> {
XsuaaCredentials xsuaaCredentials = (new ServiceCredentialsRetriever()).getClientCredentials("destination");
AccessToken accessToken;
if (propagateUser) {
accessToken = xsuaaService.retrieveAccessTokenViaUserTokenExchange(xsuaaCredentials.getXsuaaUri(), xsuaaCredentials.getCredentials(), useProviderTenant);
} else {
accessToken = xsuaaService.retrieveAccessTokenViaClientCredentialsGrant(xsuaaCredentials.getXsuaaUri(), xsuaaCredentials.getCredentials(), useProviderTenant);
}
return this.fetchDestinationsJson(servicePath, accessToken);
}, ResilienceConfiguration.of(DestinationService.class).isolationMode(ResilienceIsolationMode.TENANT_OPTIONAL).timeLimiterConfiguration(TimeLimiterConfiguration.of().timeoutDuration(Duration.ofSeconds(6L))).circuitBreakerConfiguration(CircuitBreakerConfiguration.of().waitDuration(Duration.ofSeconds(6L))));
Steven
I'm not the most experienced in this specific part, but looking at your code it seems fine to me. When a server returns 404 Not found it's not an indication of a service failure or error, but that resource is simply not found. If in your case 404 means that an error took place and the request has to be retried with a resilient approach, you have to throw that exception to inform Resilience4J that smth went wrong.
While we're working on improving our documentation, I recommend you take a look at the existing tutorial explaining resilience within the SAP Cloud SDK context. There we also throw ResilienceRuntimeException for clarity:
public List<BusinessPartner> execute() {
return ResilienceDecorator.executeSupplier(this::run, myResilienceConfig, e -> {
logger.warn("Fallback called because of exception.", e);
return Collections.emptyList();
});
}
private List<BusinessPartner> run() {
try {
return businessPartnerService
.getAllBusinessPartner()
.select(BusinessPartner.BUSINESS_PARTNER,
BusinessPartner.LAST_NAME,
BusinessPartner.FIRST_NAME,
BusinessPartner.IS_MALE,
BusinessPartner.IS_FEMALE,
BusinessPartner.CREATION_DATE,
BusinessPartner.TO_BUSINESS_PARTNER_ADDRESS
.select(BusinessPartnerAddress.CITY_NAME,
BusinessPartnerAddress.COUNTRY,
BusinessPartnerAddress.TO_EMAIL_ADDRESS
.select(AddressEmailAddress.EMAIL_ADDRESS)
)
)
.filter(BusinessPartner.BUSINESS_PARTNER_CATEGORY.eq(CATEGORY_PERSON))
.orderBy(BusinessPartner.LAST_NAME, Order.ASC)
.top(200)
.execute(destination);
} catch (ODataException e) {
throw new ResilienceRuntimeException(e);
}
}
Regarding the code snippet from the DestinationService, I believe that fetchDestinationsJson() method throws an implicit exception thus letting Resilience4J know that smth went wrong. While in your case HttpClient won't throw anything when receiving 404 as it's a correct response code as any other.
I also think that checking CircuitsBreaker examples from Resilience4J library might be helpful.
I hope it helps:)
No you do not have to throw a ResilienceRuntimeException. In fact the SDK only uses that to wrap checked and unchecked exceptions into an unchecked exception which wraps all kinds of failures that occur within a resilient call.
Please expand your question with more details, I'll then expand this answer:
Which version of the SDK are you using?
How (and how often) do you invoke the decorated callable? Please expand the code block.
Please specify the exact behaviour you observe. What exception is thrown when you invoke the decorated callable? If the circuit breaker opens this should be a CallNotPermittedException wrapped inside a ResilienceRuntimeException
Reduce the callable to simply throw an exception in order to simplify the code
Reduce the resilience configuration to only use a circuit breaker (leverage ResilienceConfiguration.empty()). If that works add stuff back in again until it doesn't.
For reference also please find the documentation of resilience4j which the SDK uses under the hood to perform resilient operations.
I have a method written in a Grails service, which processes a lot of data.
I noticed that, sometimes, the method returns success but the data is not persisted to the database.
I debugged it, following all the data till the end of the method and everything is fine, however data is not persisted.
The following image demonstrates the what I just explained. You can see the end of the method, in which a Map object is filled with persistent object metadata. Even you can see the console which contains the printend Hibertate SQL
How can I detect whether a rollback mechanism is thrown after successful method returning?
This is my connection properties for Oracle 12c database. Others configurations are Grails defaults
dataSource.pooled=true
hibernate.jdbc.use_get_generated_keys=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=false
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
dataSource.driverClassName=oracle.jdbc.driver.OracleDriver
dataSource.dialect=org.hibernate.dialect.OracleDialect
dataSource.url=jdbc:oracle:thin:#172.16.1.20:1521:db
dataSource.username=<USER>
dataSource.password=<PASS>
hibernate.default_schema=<SCHEMA>
The service is anotated as #Transactional
#Transactional
class SincronizacionService {
}
Any Idea?
When using GORM's save method, also use failOnError:true. By default, save method silently fails. However, if you use failOnError:true, it will throw an exception if the data is not persisted.
If you do not want to stop the program when the data fails to save, you can use the try-catch block to log data that failed to save and let the algorithm continue to do it work.
Hope that helps.
I found the problem. In this method actaDenunciaService.generarActaDenuncia(denuncia), there is a peculiarity. In a part of the method is located the following snippet:
try {
DNomenclador nomenclador = nomencladorService.obtenerNomencladorDNomenclador(meta.valor.toLong())
if (!nomenclador) {
return toReturn(limpiarTexto(meta.valor))
} else {
return toReturn(nomenclador.valor)
}
} catch (Exception e) {
return toReturn(limpiarTexto(meta.valor))
}
A team member changed this line nomencladorService.obtenerNomencladorDNomenclador(meta.valor.toLong()). The change represented a huge improvement of memory saving. However, the team member did not take into account a business process, which does not take into account the method he used.
Yes, a runtime exception is being thrown.
And the treatment, depending on the objective of the method, is correct
For the future, this is how the method will be from now on:
try {
DNomenclador nomenclador = nomencladorService.obtenerNomencladorDNomencladorLibre(meta.valor.toLong())
if (!nomenclador) {
return toReturn(limpiarTexto(meta.valor))
} else {
return toReturn(nomenclador.valor)
}
} catch (Exception e) {
e.printStackTrace()
return toReturn(limpiarTexto(meta.valor))
}
nomencladorService.obtenerNomencladorDNomencladorLibre(meta.valor.toLong()) for the business process
e.printStackTrace() for tracing any other peculiarity
Thanks a lot to everybody who had collaborated on finding this error
I found the error!
An error thrown inside a method for generating a PDF document with data, appearsto be failing. The second line shows this
try {
denuncia.xmlFirmadoServ = dfileManagerService.guardarDFile(signatureResponse.resultado, "xmlfirmadoservidor.xml", usuario)
denuncia = actaDenunciaService.generarActaDenuncia(denuncia).denuncia
} catch (Throwable t) {
denunciaUtilService.incrementarNumeroDenuncia(true)
throw t
}
Now, the new question is: If the method is encapsulated inside a try/catchblock, why the catch block is not excecuting?
When I comment the 2nd line inside try/catch block, data is persisted on database
With no comments, generation PDF method is executed till the end, doing all what it must do
I need to catch any front end (angulardart) error and send it back to the server.
I saw there is something like his in regular Angular ErrorHandler, but I can't find any equivalent in angular dart (or dart it self).
Maybe I should hack the Exception object's constructor, but I don't find it a good approach (assuming it's possible)
any hints please?
In Dart it's quite similar:
#Injectable()
class ErrorHandler implements ExceptionHandler {
ApplicationRef _appRef;
ErrorHandler(Injector injector) {
// prevent DI circular dependency
new Future<Null>.delayed(Duration.ZERO, () {
_appRef = injector.get(ApplicationRef) as ApplicationRef;
});
}
#override
void call(dynamic exception, [dynamic stackTrace, String reason]) {
final stackTraceParam = stackTrace is StackTrace
? stackTrace
: (stackTrace is String
? new StackTrace.fromString(stackTrace)
: (stackTrace is List
? new StackTrace.fromString(stackTrace.join('\n'))
: null));
_log.shout(reason ?? exception, exception, stackTraceParam);
// We can try to get an error shown, but don't assume the app is
// in a healthy state after this error handler was reached.
// You can for example still instruct the user to reload the
// page with danger to cause hare because of inconsistent
// application state..
// To get changes shown, we need to explicitly invoke change detection.
_appRef?.tick();
}
}
Provide the error handler
return bootstrap(AppComponent, [const Provide(ExceptionHandler, useClass: ErrorHandler)]);
For errors that might be caused outside Angular, see also How to catch all uncaught errors in a dart polymer app?
I've been trying to setup a simple Serversocket and I would like to have an exception thrown (other than some other stuff ie. setting a var to false) if some error is encountered, it works using an external callback but what about closures?
The Dart editor gives me an error and refuses to run it!
Server(String address,int port,int backlog)
{
this.s = new ServerSocket(address,port,backlog);
this.s.onError = (e) => throw new Exception(e);
}
I've tried also "throw e" and stuff like that, but as long as "throw" is present the ide won't run it.
I have had the same problem, Dart seams to be unable to accepts throws in single line closures. You should be able to do:
Server(String address,int port,int backlog)
{
this.s = new ServerSocket(address,port,backlog);
this.s.onError = (e) {
throw new Exception(e);
};
}
I have not looked in the spec so I don't know if its intentional or is a bug.