Scala, Akka-Http and mysql - Too slow - java

I tried to connect MySQL to my scala-Akka code. In the receive method, I have 3 URL's and for these URL's, I implemented a simple hit counter.
So whenever I visit that particular URL, I insert a row into a table which will be the (URL, count, its timestamp). But I noticed its too slow. Completing only 180 requests in 10 seconds! What can I do to improve performance? Please help!
import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.pattern.ask
import akka.stream.ActorMaterializer
import akka.util.Timeout
import scala.concurrent.duration._
import scala.io.StdIn
import java.sql.{Connection, DriverManager, PreparedStatement, Timestamp}
import java.time.{LocalDateTime, LocalTime}
import java.util.Date
import akka.http.javadsl.server.Route
object DBCP3 {
final case class fetch1(param:String)
val sql = "INSERT INTO URLInfo (url, time, count)" + "VALUES (?, ?, ?)"
val url = "jdbc:mysql://127.0.0.1/url"
val driver = "com.mysql.jdbc.Driver"
val username = "root"
val password = "SomePassword"
Class.forName(driver)
var connection = DriverManager.getConnection(url, username, password)
val date = new Date
private var number1: Int = 0
private var number3: Int = 0
private var number2: Int = 0
def insertIntoDB(path: String, num: Int) = {
val stm: PreparedStatement = connection.prepareStatement(sql)
stm.setString(1, path)
stm.setTimestamp(2, new Timestamp(date.getTime))
stm.setInt(3, num)
stm.execute()
}
class ActorA extends Actor with ActorLogging {
def receive = {
case fetch1(param) =>
if(param=="path1") {
number1+=1
insertIntoDB("http://localhost:8080/path1",number1)
context.sender() ! number1
}
if(param=="path2") {
number2+=1
insertIntoDB("http://localhost:8080/path2",number2)
context.sender() ! number2
}
if(param=="path3") {
number3+=1
insertIntoDB("http://localhost:8080/path3",number3)
context.sender() ! number3
}
}
}
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
implicit val timeout: Timeout = 1.seconds
val actor1 = system.actorOf(Props[ActorA], "SimpleActor1")
val route = concat(
path("path1") {
get {
onComplete((actor1 ? fetch1("path1")).mapTo[Int])
{
number => complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, s"<h1>You visited $number times</h1>"))
}
}
},
path("path2") {
onComplete((actor1 ? fetch1("path2")).mapTo[Int])
{
number => complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, s"<h1>You visited $number times</h1>"))
}
},
path("path3") {
onComplete((actor1 ? fetch1("path3")).mapTo[Int])
{
number => complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, s"<h1>You visited $number times</h1>"))
}
}
)
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
val _ = bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
connection.close()
}
}

Related

How to show Realm Data base results to an edit text?

so I'm new to realm data base and I'm trying to show the data that the user wrote throw an Edit text and show it in a Textview..
My realm class
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
#RealmClass
open class GoodStudents : RealmObject(){
#PrimaryKey
var id: Long = 0
var name : String? = null
var grade : Int? = null
}
Main activity code
Realm.init(this)
val convig = RealmConfiguration.Builder()
.name("GoodStudents").build()
val realm = Realm.getInstance(convig)
realm.beginTransaction()
count = realm.where(GoodStudents::class.java).findAll().size
val goodStudents = realm.createObject(GoodStudents::class.java, count+1)
goodStudents.name = name.text.toString()
goodStudents.grade
realm.commitTransaction()
val readData = realm.where(GoodStudents::class.java).findAll()
saveButton.setOnClickListener {
Toast.makeText(this,"Data is saved", Toast.LENGTH_LONG).show()
var text = text.text
readData.forEach { save ->
save.name = text as String?
}
}
P.C. Java code is acceptable..
so I found out that writing this code will work
saveButton.setOnClickListener {
val convig = RealmConfiguration.Builder()
.name("GoodStudents").build()
val realm = Realm.getInstance(convig)
realm.beginTransaction()
count = realm.where(GoodStudents::class.java).findAll().size
val goodStudents = realm.createObject(GoodStudents::class.java, count+1)
goodStudents.name = name.text.toString()
goodStudents.grade = grade.text.toString().toInt()
val readData = realm.where(GoodStudents::class.java).findAll()
readData.forEach { save ->
text.text = "" + save.name + ": " + goodStudents.grade
}
realm.commitTransaction()
}

How to measure upload speed when using HttpURLConnection while the upload is on-going without setting chunkedStreamingMode?

I'm trying to measure the upload speed of a client application I'm creating.
Similarly to another question I had for the download speed, I'm trying to do that while the upload is on-going and update the avg upload speed on a GUI.
I tried measuring the speed that the data are being written in the output stream of the HttpsURLConnection but eventually I realized that the HttpsURLConnection by default it buffers some of the data and it doesn't send it until the method getResponseCode() or getInputStream() is called.
Calling and setting setChunkedStreamingMode(int) helps to measure more accurately the speed with the below example, but the server application unfortunately doesn't support that, so I am trying to figure out if there is a different way or approach.
Example:
import com.sun.net.httpserver.*
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.net.HttpURLConnection
import java.net.InetSocketAddress
import java.net.URL
import java.util.*
import javax.net.ssl.HttpsURLConnection
import kotlin.system.measureNanoTime
import kotlin.system.measureTimeMillis
fun main(args: Array<String>) {
val PORT = 49831
val serverT = Thread {
val s = HttpServer.create()
s.bind(InetSocketAddress(PORT),0)
s.executor = null
s.createContext("/") {httpExchange ->
val request = httpExchange.requestBody.readBytes()
val response = "This is the response".toByteArray()
val headers = httpExchange.getResponseHeaders()
headers.add("Access-Control-Allow-Methods","OPTIONS,GET,POST")
headers.add("Access-Control-Allow-Origin","*")
httpExchange.sendResponseHeaders(200, response.size.toLong())
val os = httpExchange.responseBody
os.write(response)
os.close()
println("Server: Finished sending response.")
s.stop(0)
}
s.start()
}
serverT.start()
val client = TestHttpClient("127.0.0.1", PORT)
val byteArr = ByteArray(1024*1024*100) {'a'.toByte()}
client.sendRequestSynchronous(byteArr.inputStream(), requestMethod = "POST", measureSpeed = {it ->
println("Avg speed: ${it.getOverallTransferRate()} MB/s")
})
}
class TestHttpClient (val serverHostname: String, val serverPort: Int) {
/**
* Sends a request to the server with the content of the data InputStream, at the specified uri. You can specify the request method and add any headers on the request by using the respective parameters.
* #param data The data input stream that will be sent to the server
* #param uri The URI that the request will be sent to
* #param requestMethod The type of the HTTP request
* #param headers The headers of the request
* #param measureSpeed A function which is being called to update the statistics of this request
*/
fun sendRequestSynchronous(data: InputStream, uri: String = "/", requestMethod: String = "POST", headers: Map<String, String> = HashMap(), measureSpeed : (NetworkStatistics) -> Unit = { }) : Triple<Int, MutableMap<String, MutableList<String>>, InputStream> {
val path = "http://$serverHostname:$serverPort$uri"
val connection = if (path.startsWith("https://")) (URL(path).openConnection() as HttpsURLConnection) else URL(path).openConnection() as HttpURLConnection
connection.doInput = true
connection.doOutput = true
connection.requestMethod = requestMethod
//connection.setChunkedStreamingMode(64*1024) // Uncomment this line to have a better measurement of the speed
headers.forEach {
connection.addRequestProperty(it.key, it.value)
}
connection.connect()
println("Client connected!")
val totalAmountBytesToSend = data.available() // amount of bytes of the whole request
val statistics = NetworkStatistics(totalAmountBytesToSend.toLong())
val timeMeas = measureTimeMillis {
copy(data, connection.outputStream, statistics, {it -> measureSpeed(it)} )
}
println("Time measured for upload: $timeMeas")
val timeMeas2 = measureTimeMillis {
connection.outputStream.flush()
}
println("Time measured for flushing output stream: $timeMeas2")
var code = 200
val timeMeas3 = measureTimeMillis {
code = connection.responseCode
}
println("Time measured for reading the connection response code: $timeMeas3")
return Triple(code, connection.headerFields, connection.inputStream)
}
private val BUFFER_SIZE = 8192
#Throws(IOException::class)
private fun copy(source: InputStream, sink: OutputStream, networkStatistics: NetworkStatistics, measureSpeed : (NetworkStatistics) -> Unit = { }): Long {
var nread = 0L
val buf = ByteArray(BUFFER_SIZE)
var n: Int
n = source.read(buf)
while (n > 0) {
val nano = measureNanoTime {
sink.write(buf, 0, n)
nread += n.toLong()
n = source.read(buf)
}
networkStatistics.dataSent = nread
networkStatistics.totalSendingTime += nano
networkStatistics.lastPacketBytes = n.toLong()
networkStatistics.lastPacketTime = nano
measureSpeed(networkStatistics)
}
return nread
}
}
class NetworkStatistics(var totalAmountData: Long, var dataSent: Long = 0, var totalSendingTime: Long = 0, var lastPacketBytes: Long = 0, var lastPacketTime: Long = 0) {
private fun convertNanoToSeconds(nano: Long) : Double {
return nano.toDouble() / 1000000000
}
private fun convertBytesToMegabytes(bytes: Long) : Double {
return bytes.toDouble()/1048576
}
private fun convertBytesNanoToMegabytesSeconds(bytes: Long, nano: Long) : Double {
return ( bytes.toDouble() / nano.toDouble() ) * 953.67431640625
}
/**
* Returns the transfer rate of the last packet in MB per second.
*/
fun getLastPacketRate() : Double {
return if (lastPacketTime != 0L) {
convertBytesToMegabytes(lastPacketBytes) / convertNanoToSeconds(lastPacketTime)
}
else
0.0
}
/**
* Returns the transfer rate that has been measured by this instance in MB per second.
*/
fun getOverallTransferRate() : Double {
return if (totalSendingTime != 0L) {
convertBytesNanoToMegabytesSeconds(dataSent, totalSendingTime)
}
else
0.0
}
/**
* Returns the percent of the transfer that has been completed.
*/
fun getTransferCompletePercent() : Double {
return if (totalAmountData != 0L) {
(dataSent.toDouble() / totalAmountData) * 100
}
else
0.0
}
}

How to add Status = KO in Gatling script?

Is it possible to fail my request?
I would like to put Status = KO in asLongAs() section. My condition is like, if I get WorkflowFailed = True or Count > 8 then I want to fail that request using Status = KO.
I have seen somewhere about session.markAsFailed but how and where to use this?
Thanks.
Here is the code,
class LaunchResources extends Simulation {
val scenarioRepeatCount = Integer.getInteger("scenarioRepeatCount", 1).toInt
val userCount = Integer.getInteger("userCount", 1).toInt
val UUID = System.getProperty("UUID", "24d0e03")
val username = System.getProperty("username", "p1")
val password = System.getProperty("password", "P12")
val testServerUrl = System.getProperty("testServerUrl", "https://someurl.net")
val count = new java.util.concurrent.atomic.AtomicInteger(0)
val httpProtocol = http
.baseURL(testServerUrl)
.basicAuth(username, password)
.connection("""keep-alive""")
.contentTypeHeader("""application/vnd+json""")
val headers_0 = Map(
"""Cache-Control""" -> """no-cache""",
"""Origin""" -> """chrome-extension://fdmmgasdw1dojojpjoooidkmcomcm""")
val scn = scenario("LaunchAction")
.repeat (scenarioRepeatCount) {
exec(http("LaunchAResources")
.post( """/api/actions""")
.headers(headers_0)
.body(StringBody(s"""{"UUID": "$UUID", "stringVariables" : {"externalFilePath" : "/Test.mp4"}}"""))
.check(jsonPath("$.id").saveAs("WorkflowID")))
.exec(http("SaveWorkflowStatus")
.get("""/api/actions/{$WorkflowID}""")
.headers(headers_0)
.check(jsonPath("$.status").saveAs("WorkflowStatus")))
}
.asLongAs(session => session.attributes("WorkflowStatus") != "false" && count.getAndIncrement() < 8) {
doIf(session => session("WorkflowFailed").validate[String].map(WorkflowFailed => !WorkflowFailed.contains("true")).recover(true))
{
pause(pauseTime)
.exec(http("SaveWorkflowStatus")
.get("""/api/actions/${WorkflowID}""")
.headers(headers_0)
.check(jsonPath("$.running").saveAs("WorkflowStatus"))
.check(jsonPath("$.failed").saveAs("WorkflowFailed")))
.exec(session => {
val wflowStatus1 = session.get("WorkflowStatus").asOption[String]
val wflowFailed1 = session.get("WorkflowFailed").asOption[String]
println("Inner Loop Workflow Status: ========>>>>>>>> " + wflowStatus1.getOrElse("COULD NOT FIND STATUS"))
println("Inner Loop Workflow Failed?? ========>>>>>>>> " + wflowFailed1.getOrElse("COULD NOT FIND STATUS"))
println("Count =====>> " + count)
session})
}
}
setUp(scn.inject(atOnceUsers(userCount))).protocols(httpProtocol)
}
there's a method available on the session
exec(session => session.markAsFailed)

Scala how to inject mock object to ScalatraFlatSpec

I stuck with Unit test in Scala for many days. I cannot inject mock object to Unit test. The ScalatraFlatSpec call to the actual database not my mock variable and i have no idea to do.
This is my API
class Dashboard extends Servlet {
get("/:brand_code") {
val start = System.currentTimeMillis
val brandCode = params.get("brand_code").get
var brandId = 0;
val sqlFind = "SELECT DISTINCT(id) FROM brands WHERE brand_code=?"
val found:List[Map[String, Any]] = ConnectionModel.getExecuteQuery(sqlFind, List(brandCode))
if(found.isEmpty){
halt(404, send("error", s"brand_code [$brandCode] not found."))
}else{
brandId = found(0).getOrElse("id", 0).toString.toInt
send("Yeah55", brandId)
}
}
And this is Servlet
abstract class Servlet extends ScalatraServlet with CorsSupport with JacksonJsonSupport {
protected implicit lazy val jsonFormats: Formats = DefaultFormats.withBigDecimal
protected override def transformResponseBody(body: JValue): JValue = body.underscoreKeys
protected lazy val body = parsedBody.extract[Map[String, Any]]
protected def send(message: String, data: Any = None) = Map("message" -> message, "data" -> data)
options("/*") {
response.setHeader(
"Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers")
)
}
before() {
contentType = formats("json")
}
}
And this is ConnectionModel and ConnectionModelAble
trait ConnectionModelAble {
def getExecuteQuery(sql: String, parameters: List[Any]): List[Map[String, Any]]
}
object ConnectionModel extends ConnectionModelAble{
var connection:Connection = {
val url = "jdbc:mysql://localhost:3306/db"
val username = "root"
val password = ""\
Class.forName("com.mysql.jdbc.Driver")
DriverManager.getConnection(url, username, password)
}
def getExecuteQuery(sql: String, parameters: List[Any]): List[Map[String, Any]]= {
try {
val statement = connection.createStatement()
var preparedStatement: PreparedStatement = connection.prepareStatement(sql);
var formatDate: DateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
// Do some execute
for (i <- 0 until parameters.size) {
parameters(i) match {
case _: Int => preparedStatement.setInt(i + 1, parameters(i).toString.toInt)
case _: Double => preparedStatement.setDouble(i + 1, parameters(i).toString.toDouble)
case _: Date => preparedStatement.setDate(i + 1, new java.sql.Date(formatDate.parse(parameters(i).toString).getTime))
case default => preparedStatement.setString(i + 1, parameters(i).toString)
}
}
val resultSet = preparedStatement.executeQuery()
val metaData: ResultSetMetaData = resultSet.getMetaData();
val columnCount = metaData.getColumnCount();
var ret: List[Map[String, Any]] = List();
while (resultSet.next()) {
var row: Map[String, Any] = Map[String, Any]();
for (i <- 1 to columnCount) {
val columnName = metaData.getColumnName(i);
var obj = resultSet.getObject(i);
row += columnName -> obj
}
ret = ret :+ row
}
ret
}catch {
case e: Exception => {
e.printStackTrace();
List()
}
}
}
And this is my unit test
class DashboardSpec extends ScalatraFlatSpec with MockitoSugar {
addServlet(new Dashboard, "/v1/dashboard/*")
it should "return get dashboard correctly" in {
val brandCode = "APAAA"
val brandId = 157
get("/v1/dashboard/APAAA") {
val connectModel = mock[ConnectionModelAble]
val sqlFind = "SELECT DISTINCT(id) FROM brands WHERE brand_code=?"
Mockito.when(connectModel.getExecuteQuery(sqlFind, List(brandCode))).thenReturn(
List(Map("id" -> 150))
)
assert(status == 200)
println(connectModel.getExecuteQuery(sqlFind, List(brandCode)))
println(body)
}
}
}
I found that body from unit test is not from my mock data, it's from real database. What should i do.
Thank you.
You aren't injecting your mock into the Dashboard, so the Connection you're seeing in getExecuteQuery is the one provided by ConnectionModel.connection. You probably want to use a dependency injection framework or something like the Cake pattern to make sure your Dashboard is referring to your mock instance.

How would I import tables into another class (/object??) so I can run queries on it in the other class/object? [slick 3.0][scala]

I have two tables defined in a
class Patients(tag: Tag) extends Table[(String, String, Int, String)](tag, "Patientss") {
def PID = column[String]("Patient Id", O.PrimaryKey)
def Gender = column[String]("Gender")
def Age = column[Int]("Age")
def Ethnicity = column[String]("Ethnicity")
def * = (PID, Gender, Age, Ethnicity)
}
val patientsss = TableQuery[Patients]
class DrugEffect(tag: Tag) extends Table[(String, String, Double)](tag, "DrugEffectss") {
def DrugID = column[String]("Drug ID", O.PrimaryKey)
def PatientID = column[String]("Patient_ID")
def DrugEffectssss = column[Double]("Drug Effect")
def * = (DrugID, PatientID, DrugEffectssss)
def Patient = foreignKey("Patient_FK", PatientID, patientsss)(_.PID)
}
val d_effects = TableQuery[DrugEffect]
I fill in the tables in this particular object/class as well.
I was wondering how I could call the filled in tables in another object so I can access both DrugEffect and Patients as a class, and then run queries on the table itself?
I hope I'm making myself clear, I don't really have a clue about what I'm doing
What I mean by running queries is something like this:
val q1 = for {
c <- patientsss if (c.Age === 20 && c.Gender === "F")
s <- d_effects if (s.DrugEffectssss > 10.0)
} yield (c.PID, s.DrugID)
but in an object defined in a different file
You need the DB API and the table in the separate class. You can do something like:
import tables.Tables
class SeparateClass extends HasDatabaseConfig[JdbcProfile] {
val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
import driver.api._
def get(id: Long) = {
db.run(Tables.DrugEffect.d_effects.filter(_.id === id).result)
}
}

Categories