diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 65ba13676b50082e68d9cba7313d56cfca3637e4..c0d6a6b53b2ac36ff6d73cbc89fd08cd1748f79b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,7 @@ variables: MYSQL_ROOT_PASSWORD: arsnova3_prototype WAR_FILE: target/scala-2.11/arsnova-3-backend*.jar MIRROR_REPO: git@github.com:thm-projects/arsnova-3-backend.git + REPORT_DIR: target/gatling-it/stresstest* stylecheck: stage: test @@ -44,6 +45,20 @@ sync_mirror: - git update-ref -d refs/tags/staging - git push --mirror "$MIRROR_REPO" +stresstest: + stage: test + only: + - master + - /^v[0-9]+/ + tags: + - sbt + dependencies: [] + script: + - sbt clean gatling-it:test + artifacts: + paths: + - $REPORT_DIR + package: stage: build only: diff --git a/build.sbt b/build.sbt index 6e4c647412c5083fda9e9bcaec191e07a2fb9719..bac23aca85a46fd3743c999cc25771e4518e6481 100644 --- a/build.sbt +++ b/build.sbt @@ -1,8 +1,12 @@ name := "arsnova-3-backend" +name := "arsnova-3-backend" + version := "0.0.1" -scalaVersion := "2.12.1" +scalaVersion := "2.11.8" + +enablePlugins(GatlingPlugin) libraryDependencies ++= { val akkaVersion = "2.4.17" @@ -10,6 +14,7 @@ libraryDependencies ++= { val scalaTestVersion = "3.0.0" val scalaMockVersion = "3.2.2" val slickVersion = "3.2.0" + val gatlingVersion = "2.2.4" Seq( "com.typesafe.akka" %% "akka-actor" % akkaVersion, @@ -23,9 +28,11 @@ libraryDependencies ++= { "org.slf4j" % "slf4j-nop" % "1.7.21", "mysql" % "mysql-connector-java" % "6.0.3", "org.flywaydb" % "flyway-core" % "3.2.1", - "org.scalatest" %% "scalatest" % scalaTestVersion + "org.scalatest" %% "scalatest" % scalaTestVersion, + "io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion % "test,it", + "io.gatling" % "gatling-test-framework" % gatlingVersion % "test,it" ) } // skip Tests in assembly job -test in assembly := {} +test in assembly := {} \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index 192a8dc02c4ace0223773a052642d207d10ac343..48dfdc7841d21f5b8defe30d48f25f31733ba411 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,4 @@ addSbtPlugin("io.spray" % "sbt-revolver" % "0.8.0") addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3") +addSbtPlugin("io.gatling" % "gatling-sbt" % "2.2.1") diff --git a/src/it/scala/de/thm/arsnova/Stresstest.scala b/src/it/scala/de/thm/arsnova/Stresstest.scala new file mode 100644 index 0000000000000000000000000000000000000000..4865e7afb21e835fc934f799f8a98f449a3e90fe --- /dev/null +++ b/src/it/scala/de/thm/arsnova/Stresstest.scala @@ -0,0 +1,42 @@ +package de.thm.arsnova + +import de.thm.arsnova.auditor.BasicAuditorSimulation +import de.thm.arsnova.tutor.BasicTutorSimulation + +import io.gatling.core.Predef._ // 2 +import io.gatling.http.Predef._ +import scala.concurrent.duration._ + +class Stresstest extends Simulation { + println("starting webserver") + WebServer.main(Array()) + + val httpProtocol = http + .baseURL("http://localhost:9000") + .inferHtmlResources(BlackList(""".*\.css""", """.*\.js""", """.*\.ico"""), WhiteList()) + .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") + .acceptEncodingHeader("gzip, deflate") + .acceptLanguageHeader("en-US,en;q=0.5") + .doNotTrackHeader("1") + .userAgentHeader("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0") + + val headers_0 = Map("Upgrade-Insecure-Requests" -> "1") + + val uri1 = "http://localhost:9000/session/1" + + val auditorScn = scenario("Test").exec( + BasicAuditorSimulation.joinSession.pause(3), + BasicAuditorSimulation.getAllPrepQuestions.pause(3), + BasicAuditorSimulation.answerToMCQuestion + ) + + val tutorScn = scenario("Basic Tutor").exec( + BasicTutorSimulation.createSession.pause(3), + BasicTutorSimulation.createQuestion + ) + + setUp( + auditorScn.inject(rampUsers(1000) over (5 seconds)), + tutorScn.inject(rampUsers(100) over (5 seconds)) + ).protocols(httpProtocol) +} \ No newline at end of file diff --git a/src/it/scala/de/thm/arsnova/auditor/BasicAuditorSimulation.scala b/src/it/scala/de/thm/arsnova/auditor/BasicAuditorSimulation.scala new file mode 100644 index 0000000000000000000000000000000000000000..0e770e9e275ffdbae582313c42ef0484796d6dcd --- /dev/null +++ b/src/it/scala/de/thm/arsnova/auditor/BasicAuditorSimulation.scala @@ -0,0 +1,28 @@ +package de.thm.arsnova.auditor + +import de.thm.arsnova.models.ChoiceAnswer + +import io.gatling.core.Predef._ // 2 +import io.gatling.http.Predef._ +import scala.concurrent.duration._ +import spray.json._ +import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ + +object BasicAuditorSimulation { + import de.thm.arsnova.mappings.ChoiceAnswerJsonProtocol._ + + val joinSession = exec(http("Auditor joins session") + .get("/session/1")) + + val getAllPrepQuestions = exec(http("Auditor gets all preparation questions") + .get("/question/") + .queryParam("sessionid", "1") + .queryParam("variant", "preparation")) + + val newAnswer = ChoiceAnswer(None, 5, 1, 2) + + val answerToMCQuestion = exec(http("Auditor answers mc question") + .post("/question/5/choiceAnswer") + .header("Content-Type", "application/json") + .body(StringBody(newAnswer.toJson.toString)).asJSON) +} \ No newline at end of file diff --git a/src/it/scala/de/thm/arsnova/tutor/BasicTutorSimulation.scala b/src/it/scala/de/thm/arsnova/tutor/BasicTutorSimulation.scala new file mode 100644 index 0000000000000000000000000000000000000000..40c8d83db80ceffeb694e962e27f9e7672273b46 --- /dev/null +++ b/src/it/scala/de/thm/arsnova/tutor/BasicTutorSimulation.scala @@ -0,0 +1,38 @@ +package de.thm.arsnova.tutor + +import de.thm.arsnova.models.{AnswerOption, Question, Session} + +import io.gatling.core.Predef._ +import io.gatling.http.Predef._ +import scala.concurrent.duration._ +import spray.json._ +import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ +import java.util.Calendar + +object BasicTutorSimulation { + import de.thm.arsnova.mappings.QuestionJsonProtocol._ + import de.thm.arsnova.mappings.SessionJsonProtocol._ + + val now = Calendar.getInstance.getTime.toString + val newSession = Session(None, "12312312", 1, "A new Session", "ans", now, now, true, false, false, None) + + val mcAnswerOptions = Seq( + AnswerOption(None, None, false, "12", -10), + AnswerOption(None, None, true, "13", 10), + AnswerOption(None, None, false, "14", -10), + AnswerOption(None, None, true, "thirteen", 10) + ) + val newMCQuestion = Question(None, 1, "new Question Subject", "This is an MC question for stress testing", + "preparation", "mc", Some("This is the hint!"), Some("The answer is 13"), true, false, true, true, false, None, Some(mcAnswerOptions)) + + val createSession = exec(http("Tutor creates session") + .post("/session/") + .header("Content-Type", "application/json") + .body(StringBody(newSession.toJson.toString)).asJSON) + + val createQuestion = exec(http("Tutor creates mc question") + .post("/question/") + .header("Content-Type", "application/json") + .body(StringBody(newMCQuestion.toJson.toString)).asJSON + ) +} \ No newline at end of file diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 70b1d1e4f3f31bdcc72ffc0745ac7591e7c8a974..cb30b59fc3cff5dce5c081a7a6bfc1eb481e2d8b 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1,5 +1,16 @@ akka { loglevel = WARNING + http { + server { + idle-timeout = 60s + request-timeout = 20s + bind-timeout = 1s + } + host-connection-pool { + max-connections = 4 + idle-timeout = 30s + } + } } database = { @@ -9,10 +20,17 @@ database = { user = ${?PSQL_USER} password = "arsnova3_prototype" password = ${?PSQL_PASSWORD} - driver = com.mysql.jdbc.Driver - numThreads = 1 - connectionPool = disabled + driver = com.mysql.cj.jdbc.Driver + connectionPool = "HikariCP" + numThreads = 10 keepAliveConnection = true + connectionTimeout = 30 seconds + maxLifetime = 5 minutes + maximumPoolSize = 10 + leakDetectionThreshold = 2000 + properties.cachePrepStmts = true + properties.prepStmtCacheSize = 20000 + properties.prepStmtCacheSqlLimit = 100000 } http { @@ -20,3 +38,5 @@ http { port = 9000 } +logger.scala.slick = DEBUG +logger.scala.slick.session = DEBUG diff --git a/src/main/scala/de/thm/arsnova/Context.scala b/src/main/scala/de/thm/arsnova/Context.scala new file mode 100644 index 0000000000000000000000000000000000000000..98eecffcd66d98a66a417d06c8d046f8f559268e --- /dev/null +++ b/src/main/scala/de/thm/arsnova/Context.scala @@ -0,0 +1,12 @@ +package de.thm.arsnova + +import akka.actor.ActorSystem +import akka.stream.ActorMaterializer + +import scala.concurrent.ExecutionContext + +object Context { + implicit val system = ActorSystem() + implicit val executor: ExecutionContext = system.dispatcher + implicit val materializer: ActorMaterializer = ActorMaterializer() +} diff --git a/src/main/scala/de/thm/arsnova/WebServer.scala b/src/main/scala/de/thm/arsnova/WebServer.scala index ba81abdefe10107e8e375c72bc0b7ec0ec55b85e..743f57ff9645cd4d60ba83ccd8d4d150df8d037c 100644 --- a/src/main/scala/de/thm/arsnova/WebServer.scala +++ b/src/main/scala/de/thm/arsnova/WebServer.scala @@ -4,16 +4,13 @@ import akka.actor.ActorSystem import akka.event.{Logging, LoggingAdapter} import akka.http.scaladsl.Http import akka.http.scaladsl.server.Directives._ -import akka.stream.ActorMaterializer import de.thm.arsnova.utils.{MigrationConfig, Config} import scala.concurrent.ExecutionContext object WebServer extends App with Config with MigrationConfig with Routes { - private implicit val system = ActorSystem() - protected implicit val executor: ExecutionContext = system.dispatcher + import de.thm.arsnova.Context._ protected val log: LoggingAdapter = Logging(system, getClass) - protected implicit val materializer: ActorMaterializer = ActorMaterializer() if (args.contains("migrate")) { migrate diff --git a/src/main/scala/de/thm/arsnova/api/ChoiceAnswerApi.scala b/src/main/scala/de/thm/arsnova/api/ChoiceAnswerApi.scala index 5a77f029c28b72d3aee0678b42a77dc58188cce3..6400744cfdde5d48a1c7f4fbe03c08a1bbb960ab 100644 --- a/src/main/scala/de/thm/arsnova/api/ChoiceAnswerApi.scala +++ b/src/main/scala/de/thm/arsnova/api/ChoiceAnswerApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.{ChoiceAnswerService, FreetextAnswerService} import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -13,6 +12,8 @@ import spray.json._ The API Interface regarding answers to choice questions (e.g. MC, SC). */ trait ChoiceAnswerApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.ChoiceAnswerJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/CommentApi.scala b/src/main/scala/de/thm/arsnova/api/CommentApi.scala index d3345c3090773d9c9c06a7059eb681406240e97b..b379cb5b4c9b44cd4a2692e2eb23db16fe505f42 100644 --- a/src/main/scala/de/thm/arsnova/api/CommentApi.scala +++ b/src/main/scala/de/thm/arsnova/api/CommentApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.CommentService import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -14,6 +13,8 @@ import spray.json._ The API Interface regarding comments (formerly known as "interposed question"), made by participants. */ trait CommentApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.CommentJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/FeaturesApi.scala b/src/main/scala/de/thm/arsnova/api/FeaturesApi.scala index 1a9cd30edc719295980b2014127f5aa628041b79..3842f35b384301c89d86a1fdf75dc8451ab7c559 100644 --- a/src/main/scala/de/thm/arsnova/api/FeaturesApi.scala +++ b/src/main/scala/de/thm/arsnova/api/FeaturesApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.FeaturesService import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -14,6 +13,8 @@ import spray.json._ The API Interface regarding session features. */ trait FeaturesApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.FeatureJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/FreetextAnswerApi.scala b/src/main/scala/de/thm/arsnova/api/FreetextAnswerApi.scala index 545bb6b9714679e2cd53e7b3c2def4c389b43866..225b011582ba4da561147ac9add354476dd71d34 100644 --- a/src/main/scala/de/thm/arsnova/api/FreetextAnswerApi.scala +++ b/src/main/scala/de/thm/arsnova/api/FreetextAnswerApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.FreetextAnswerService import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -14,6 +13,8 @@ import spray.json._ The API Interface regarding answers for the question type "freetext". */ trait FreetextAnswerApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.FreetextAnswerJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/GlobalMotdApi.scala b/src/main/scala/de/thm/arsnova/api/GlobalMotdApi.scala index d0c95166c83c52b2e754540e8b4f456731cd43fa..ff1ee4741bbeb646ca92c7fef3f9c3ef68f0d82a 100644 --- a/src/main/scala/de/thm/arsnova/api/GlobalMotdApi.scala +++ b/src/main/scala/de/thm/arsnova/api/GlobalMotdApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.GlobalMotdService import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -14,6 +13,8 @@ The API Interface regarding global messages. Only an admin should post these motd */ trait GlobalMotdApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.GlobalMotdJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/QuestionApi.scala b/src/main/scala/de/thm/arsnova/api/QuestionApi.scala index 3ba846d3b74e7e7c8fc691bf9e9d0823ea262b24..e97a64f7bdc118addd5a816b34f336399222bde9 100644 --- a/src/main/scala/de/thm/arsnova/api/QuestionApi.scala +++ b/src/main/scala/de/thm/arsnova/api/QuestionApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.QuestionService import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -14,6 +13,8 @@ import spray.json._ The API Interface regarding questions. */ trait QuestionApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.QuestionJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/SessionApi.scala b/src/main/scala/de/thm/arsnova/api/SessionApi.scala index d98f85a3008006954a57beffc6354a20fc453748..696176c2d0533faba6707f3986c9d73dfddf1e3a 100644 --- a/src/main/scala/de/thm/arsnova/api/SessionApi.scala +++ b/src/main/scala/de/thm/arsnova/api/SessionApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.SessionService import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -14,6 +13,8 @@ import spray.json._ The API Interface regarding sessions, the core component for arsnova.voting. */ trait SessionApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.SessionJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/SessionMotdApi.scala b/src/main/scala/de/thm/arsnova/api/SessionMotdApi.scala index dcc89b853323a3b51e616a661055569ef5a0470b..59af5fdae869df49392446b95e24a4fe97414ec5 100644 --- a/src/main/scala/de/thm/arsnova/api/SessionMotdApi.scala +++ b/src/main/scala/de/thm/arsnova/api/SessionMotdApi.scala @@ -4,7 +4,6 @@ import de.thm.arsnova.services.SessionMotdService import de.thm.arsnova.models._ import de.thm.arsnova.hateoas.{ApiRoutes, ResourceAdapter, Link} -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ @@ -13,6 +12,8 @@ import spray.json._ The API Interface regarding session messages. */ trait SessionMotdApi { + import de.thm.arsnova.Context.executor + // protocol for serializing data import de.thm.arsnova.mappings.SessionMotdJsonProtocol._ diff --git a/src/main/scala/de/thm/arsnova/api/UserApi.scala b/src/main/scala/de/thm/arsnova/api/UserApi.scala index f9fe0feaa95cfdf60e5a49a17b3afd9649c8ec46..29137d4c5cee9e9969d1ffa5fa81c1159a62ef0e 100644 --- a/src/main/scala/de/thm/arsnova/api/UserApi.scala +++ b/src/main/scala/de/thm/arsnova/api/UserApi.scala @@ -3,12 +3,13 @@ package de.thm.arsnova.api import de.thm.arsnova.services.UserService import de.thm.arsnova.models._ -import scala.concurrent.ExecutionContext.Implicits.global import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import akka.http.scaladsl.server.Directives._ import spray.json._ trait UserApi { + import de.thm.arsnova.Context.executor + import de.thm.arsnova.mappings.UserJsonProtocol._ val userApi = pathPrefix("") { diff --git a/src/main/scala/de/thm/arsnova/services/FeaturesService.scala b/src/main/scala/de/thm/arsnova/services/FeaturesService.scala index 57e968621655d004d822e04290a9c63bc2a45ecf..9815267f6df96fd49d34a801b5d2231189187d4d 100644 --- a/src/main/scala/de/thm/arsnova/services/FeaturesService.scala +++ b/src/main/scala/de/thm/arsnova/services/FeaturesService.scala @@ -2,11 +2,12 @@ package de.thm.arsnova.services import de.thm.arsnova.models._ import slick.driver.MySQLDriver.api._ -import scala.concurrent.{ExecutionContext, Future} -import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.Future import scala.util.{Failure, Success} object FeaturesService extends BaseService { + import de.thm.arsnova.Context.executor + def getById(featuresId: FeaturesId): Future[Features] = { featuresTable.filter(_.id === featuresId).result.head } diff --git a/src/main/scala/de/thm/arsnova/services/QuestionService.scala b/src/main/scala/de/thm/arsnova/services/QuestionService.scala index c73b6a0206eae43df5b8fa11e9ce9c7b34e1274c..0f97ee2d4eeb8defe64a7fae58822c5b24b5f6bf 100644 --- a/src/main/scala/de/thm/arsnova/services/QuestionService.scala +++ b/src/main/scala/de/thm/arsnova/services/QuestionService.scala @@ -3,10 +3,11 @@ package de.thm.arsnova.services import de.thm.arsnova.models._ import slick.driver.MySQLDriver.api._ import scala.concurrent.{ExecutionContext, Future} -import scala.concurrent.ExecutionContext.Implicits.global import scala.util.{Failure, Success} object QuestionService extends BaseService { + import de.thm.arsnova.Context.executor + def findQuestionsBySessionIdAndVariant(sessionId: SessionId, variant: String): Future[Seq[Question]] = { db.run(questionsTable.filter(q => q.sessionId === sessionId && q.variant === variant).result).map(qSeq => Future.traverse(qSeq) { q: Question => q.format match { diff --git a/src/main/scala/de/thm/arsnova/services/SessionService.scala b/src/main/scala/de/thm/arsnova/services/SessionService.scala index e74ca15e46026ad86d9be457ad0b42eb3a0f45c8..8f206c08f7e4b71c42c9a30ecdef7e2840800556 100644 --- a/src/main/scala/de/thm/arsnova/services/SessionService.scala +++ b/src/main/scala/de/thm/arsnova/services/SessionService.scala @@ -3,9 +3,10 @@ package de.thm.arsnova.services import de.thm.arsnova.models.{UserId, Session, SessionId, Features} import slick.driver.MySQLDriver.api._ import scala.concurrent.Future -import scala.concurrent.ExecutionContext.Implicits.global -object SessionService extends BaseService{ +object SessionService extends BaseService { + import de.thm.arsnova.Context.executor + def findUserSessions(userId: UserId): Future[Seq[Session]] = { val resultTupleQry = for { sessions <- sessionsTable.filter(_.userId === userId) diff --git a/src/main/scala/de/thm/arsnova/utils/DatabaseConfig.scala b/src/main/scala/de/thm/arsnova/utils/DatabaseConfig.scala index 09dfed1c4563c1c12a9544873e33fdbdc82cfe37..d2a5b3f914c2947eb4f5a2d0274b6f2b389a6a10 100644 --- a/src/main/scala/de/thm/arsnova/utils/DatabaseConfig.scala +++ b/src/main/scala/de/thm/arsnova/utils/DatabaseConfig.scala @@ -5,7 +5,5 @@ trait DatabaseConfig extends Config{ import driver.api._ - def db: Database = Database.forConfig("database") - - implicit val session: Session = db.createSession() + val db: Database = Database.forConfig("database") }