Reliably working out if your db is down with Scala Slick - scala

I am using Scala slick to work with my Mysql db.
I am wrapping all the calls using scala.util.Try
I would like to have different behaviour based on the problem
If the DB is down, ultimately I want my webapp to return a 503
If a strange query gets through to my db layer and there is a bug with my code then I want to return a 500
After some googling, it seems like you can get a wide array of different exceptions with error codes and I'm unsure what to look for.
With slick i am using the com.mysql.jdbc.driver
Thanks

Slick/MySQL will throw MySQLSyntaxErrorException for bad syntax and CommunicationsException when it's unable to reach the database.
Here's a quick example that will catch both of these types of exceptions:
try {
Database.forURL("jdbc:mysql://some-host:3306/db-name",
driver = "com.mysql.jdbc.Driver",
user="",
password="") withSession { session: Session =>
implicit val s = session
...
}
} catch {
case e: MySQLSyntaxErrorException =>
... handle the syntax error ...
// You may want to define your own Exception that wraps the MySQL one
// and adds more context
case e: CommunicationsException =>
... handle the connection error ...
}
Then, in your webapp code, you'll want to catch your custom exceptions (see the comment in the code) and return the HTTP codes accordingly.

Related

Is there support for compression in ReactiveMongo?

I am using ReactiveMongo as the connector for an Akka-Http, Akka-Streams project. I am creating the MongoConnection as shown below, but the data in the database is compressed using Snappy. No matter where I look, I can't find any mention of compression support in the ReactiveMongo documentation. When I try to connect to the Mongo database using a URL with the compressors=snappy flag, it returns an exception.
I looked through the source code and indeed it appears to have no mention of compression support at all. At this point I'm willing to accept a hack work around.
Can anyone help me please?
MongoConnection.fromString("mongodb://localhost:27017?compressors=snappy").flatMap(uri => driver.connect(uri))
Exception:
23:09:15.311 [default-akka.actor.default-dispatcher-6] ERROR akka.actor.ActorSystemImpl - Error during processing of request: 'The connection URI contains unsupported options: compressors'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
java.lang.IllegalArgumentException: The connection URI contains unsupported options: compressors
at reactivemongo.api.AsyncDriver.connect(AsyncDriver.scala:227)
at reactivemongo.api.AsyncDriver.connect(AsyncDriver.scala:203)
at reactivemongo.api.AsyncDriver.connect(AsyncDriver.scala:252)
If you need a workable example, you can try this:
(You don't actually need a MongoDB container running locally for the error to be thrown)
object ReactiveMongoCompressorIssue extends App {
import scala.concurrent.Await
import scala.concurrent.duration._
implicit val actorSystem = ActorSystem("ReactiveMongoCompressorIssue")
implicit val dispatcher: ExecutionContextExecutor = actorSystem.dispatcher
final val driver = AsyncDriver()
val url = "mongodb://localhost:27017/?compressors=snappy"
val connection = Await.result(MongoConnection.fromString(url).flatMap(uri => driver.connect(uri)), 3.seconds)
assert(connection.active)
}
Thanks to what #cchantep said about how compression in MongoDB is handled on the server side (see the MongoDB docs here) I went back through the ReactiveMongo source code to see if there was a way to either bypass the check or remove the flag from the URL myself and connect without it.
Indeed, I found that there is a boolean flag called strictMode which determines whether ignoredOptions such as the compressors flag should cause an exception to be thrown or not. So now my connection looks like this:
MongoConnection.fromString(url).flatMap(uri => driver.connect(uri, None, strictMode = false))
The None refers to a name of a connection pool, but the other connect method I was using before doesn't use one either so this works fine.
Thank you for the help!

scala return http request response of created object

I have an application with following back-end-technologies: scala/slick in playframework. Front- and back-end communicate via REST.
Now what I want to do is simply return a created/inserted (updated) row back to the front-end of my application. I thought about doing something like this:
def createClient = Action.async { implicit request =>
request.body.asJson.map(_.validate[ClientModel]) match {
case c: JsSuccess[ClientModel] =>
clientDTO.createClient(c.get).map{
cnt => Ok(Json.obj("id" -> cnt.id))
}.recover {
case e: Exception => BadRequest("Could ssnotsdreate client")
}
}
}
My code compiles but it gives me this error message while running:
XMLHttpRequest cannot load http://localhost:9002/clients. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 500.
I read about adding CORS to my application but would prefer to solve it otherwise. I thought there has to be a proper, elegant way to return a just created/inserted object back to the front-end, since it should be a core feature of any client-server communication.
I'm relatively new to scala, so please don't get hung up on my code and rather view it as pseudo code. This is a rather general question. Thank you!

Table lock timeout when executing REST API functional test in Grails 2.4.4 using an in-memory H2 database

I am trying to create a set of functional test for my REST API using the funky-spock and the rest-client-builder plugins.
My H2 DB connection string looks like this:
url = "jdbc:h2:mem:testDb:MVCC=true;LOCK_TIMEOUT=5000"
First I initialize my h2 database introducing some records in the setup() method.
And everything works fine.
def setup() {
// Clean elasticsearch index
elasticSearchService.reinitialiseIndex()
// Initialize the DB
// 1st question
questionService.createQuestionFromOccurrence(
'181718e6-fd3b-4a1b-8b40-3f83fd2965e5',
QuestionType.IDENTIFICATION,
['kangaroo', 'grey'],
userMick,
'1st question 1st comment'
)
}
But when I execute my test and perform my POST request:
RestResponse response = rest.post("http://localhost:8080/${grailsApplication.metadata.'app.name'}/ws/question") {
json([
source : 'biocache',
occurrenceId: 'f6f8a9b8-4d52-49c3-9352-155f154fc96c',
userId : userKeef.alaUserId,
tags : 'octopus, orange',
comment : 'whatever'
])
}
the process fails in the first DB operation which in this case is a get() with the following exception:
ERROR errors.GrailsExceptionResolver - JdbcSQLException occurred when processing request: [POST] /taxon-overflow/ws/question
Timeout trying to lock table "QUESTION"; SQL statement:
It looks like all DB operations within a Grails test are performed in a transaction that is rolled back after each test. Apparently it also locks the DB and since the REST request will be executed in a separate thread to the TEST, it means it cannot access the DB. And even if it was not locked the process would not see the data as it is never committed.
One way to make this work is to make the test `not transactional' by adding the attribute to your test:
class RestAPISpec extends IntegrationSpec {
static transactional = false
...
}
One of the problems with this approach is that you will have to cleanup() the database manually after each test. Here is the easiest way I found to do this:
def grailsApplication
def sessionFactory
...
def cleanup() {
(grailsApplication.getArtefacts("Domain") as List).each {
it.newInstance().list()*.delete()
}
sessionFactory.currentSession.flush()
sessionFactory.currentSession.clear()
sourceService.init()
}
Another approach is to test your REST API by testing the controller in an integrated test which is a bit cumbersome as well and it is not really and e2e testing of your web service. On the other hand it executes a bit faster than a functional test.

Spray.io test response not matching actual output

I'm trying to set up some tests for an API made by a coworker with spray.io, and I'm encountering some odd behavior. When a request results in an error for any reason, we want to return a JSON value along the lines of:
{"status":false,"message":"useful message here"}
This happens just fine in the actual browser. I have navigated to an unhandled route in the web browser, and I get the desired JSON value. So, I want to test this. Now, since I'm new to spray.io, I started off with the very simple test:
"leave GET requests to root path unhandled" in {
Get() ~> myRoute ~> check {
handled must beFalse
}
}
This went fine, no problems. Since it's my first time playing with spray.io, I looked at some of the sample tests for testing false routes, and wrapped myRoute with sealRoute() so I could check the response without failing tests:
"leave GET requests to root path unhandled" in {
Get() ~> sealRoute(myRoute) ~> check {
handled must beTrue
}
}
This also works fine. So, I decided to just make sure the text of the response was usable with this, before I went to the trouble of parsing JSON and verifying individual values:
"leave GET requests to root path unhandled" in {
Get() ~> sealRoute(myRoute) ~> check {
responseAs[String] contains "false"
}
}
This is failing. To investigate, I threw a simple line of code in to log the actual value of responseAs[String] to a file, and I got this:
The requested resource could not be found.
Can anyone tell me what I'm doing wrong? I'm thinking that one of the following is occurring:
responseAs[String] is doing more than taking the exact response and giving it back to me, applying some type of filter along the way
The framework itself is not fully evaluating the query, but rather making a mockup object for the test framework to evaluate, and therefore not executing the desired 'turn errors to json' methods that my co-worker has implemented
I have tried searching google and stack overflow specifically for similar issues, but I'm either not putting in the right queries, or most other people are content to have the default error messages and aren't trying to test them beyond checking handled must beFalse.
Edit - This is the relevant part of the RejectionHandler:
case MissingQueryParamRejection(paramName) :: _=>
respondWithMediaType(`application/json`) {
complete(BadRequest, toJson(Map("status" -> false, "message" -> s"Missing parameter $paramName, request denied")))
}
Okay, so with insight from here and a coworker, the problem has been found:
Basically, the custom RejectionHandler was defined within our custom Actor object, and it wasn't coming into scope in the tests. To resolve this, the following steps were taken:
Moved the definition for the custom RejectionHandler into its own object in a separate file (as it had to do its own imports, it was causing a "encountered unrecoverable cycle resolving import" error)
Imported this new object into both the original file and the test spec.
(fun fact - http://spray.io/documentation/1.2.2/spray-routing/key-concepts/rejections/#rejectionhandler seems to demonstrate the RejectionHandler as a top-level object but you can't have top-level implicit vals in Scala, hence the need for an object)

Scala: print a stack trace in my Scalatra app

Seems like a fairly straight forward problem, but I'd like to log a stack trace when my top level error handler in Scalatra is triggered. I'm intentionally throwing an exception in one of my methods by doing something as trivial as:
throw new IllegalArgumentException
In the error handler, the code looks like the following:
error {
case e => {
val logger = LoggerFactory.getLogger(getClass)
logger.info("an exception occurred: " + e.getStackTrace())
logger.info("the request body is: " + request)
NotFound("An error occurred, please contact support")
}
}
The error handler itself is Scalatra specific, but I'm pretty sure the answer I'm looking for can be solved using any vanilla Scala technique. Is there something I can do at this point to grab the stacktrace? I'm not sure if the request is on the same thread as the error handler, otherwise there might be some answer there. e.getStackTrace() gives me [Ljava.lang.StackTraceElement;#1f6b6954
What's the best way to get a stack trace here printed out so I can log and review it to fix errors in my terrible code?
Use ExceptionUtils from Apache Commons Lang:
import org.apache.commons.lang3.exception.ExceptionUtils
(...)
logger.info("an exception occurred: " + ExceptionUtils.getStackTrace(e))
I think you want printStackTrace() rather than getStackTrace. If you are outputting to a log file, getMessage() may be helpful. Or you may try passing the whole exception object to the logger.
If you use the standard logger: com.typesafe.scalalogging.Logger , the logger prints the stack trace for you.
You can just use it this way:
import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
try {
throw new Exception("test message")
} catch {
case e:Exception => logger.error("Exception " , e)
}
There is already an overload which is accepting 2 parameters, String and Throwable.
This question has several ways to convert an exception stack trace to a String. printStackTrace outputs to System.err unless you provide a writer.