-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Епик Александр - Phase 1 #1
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package DTOs | ||
|
||
import play.api.libs.json.{Json, Reads} | ||
|
||
case class HolderDTO(pages: Int, | ||
items: Option[Seq[VacancyDTO]]) | ||
|
||
object HolderDTO { | ||
implicit val holderDtoReader: Reads[HolderDTO] = Json.reads[HolderDTO] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package DTOs | ||
|
||
import play.api.libs.json.{Json, Reads} | ||
|
||
case class RegionDTO(id: String, | ||
name: String, | ||
areas: Seq[RegionDTO]) | ||
|
||
object RegionDTO { | ||
implicit val regionDtoReader: Reads[RegionDTO] = Json.reads[RegionDTO] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package DTOs | ||
|
||
import play.api.libs.json.{Json, Reads} | ||
|
||
case class SalaryDTO(currency: Option[String], | ||
from: Option[Int], | ||
gross: Option[Boolean], | ||
to: Option[Int]) | ||
|
||
object SalaryDTO { | ||
implicit val salaryDtoReader: Reads[SalaryDTO] = Json.reads[SalaryDTO] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package DTOs | ||
|
||
import play.api.libs.json.{Json, Reads} | ||
|
||
case class SnippetDTO(requirement: Option[String], | ||
responsibility: Option[String]) | ||
|
||
object SnippetDTO { | ||
implicit val snippetDtoReader: Reads[SnippetDTO] = Json.reads[SnippetDTO] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package DTOs | ||
|
||
import play.api.libs.json.{Json, Reads} | ||
|
||
case class VacancyDTO(id: String, | ||
name: Option[String], | ||
alternate_url: Option[String], | ||
snippet: Option[SnippetDTO], | ||
salary: Option[SalaryDTO]) | ||
|
||
object VacancyDTO { | ||
implicit val vacancyDtoReader: Reads[VacancyDTO] = Json.reads[VacancyDTO] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,13 @@ | ||
package model | ||
|
||
import java.util.UUID | ||
|
||
case class Job(id: Int, | ||
title: Option[String], | ||
requirement: Option[String], | ||
responsibility: Option[String], | ||
alternate_url: Option[String], | ||
salary_from: Option[Int], | ||
salary_to: Option[Int], | ||
salary_currency: Option[String], | ||
salary_gross: Option[Boolean], | ||
alternateUrl: Option[String], | ||
salaryFrom: Option[Int], | ||
salaryTo: Option[Int], | ||
salaryCurrency: Option[String], | ||
salaryGross: Option[Boolean], | ||
city: Option[String], | ||
key_word: Option[String]) | ||
keyWord: Option[String]) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,22 +5,37 @@ import akka.actor.ActorSystem | |
|
||
import scala.concurrent.ExecutionContext | ||
import scala.concurrent.duration._ | ||
import play.api.Configuration | ||
import play.api.{Configuration, Logger, Mode} | ||
import service.JobAggregatorService | ||
|
||
import scala.util.Try | ||
|
||
class Task @Inject()(actorSystem: ActorSystem, | ||
configuration: Configuration, | ||
jobAggregatorService: JobAggregatorService)(implicit executionContext: ExecutionContext) { | ||
|
||
val initialDelay: String = configuration.get[String]("initialDelay") | ||
val interval: String = configuration.get[String]("interval") | ||
val cities: Seq[String] = configuration.get[Seq[String]]("cities") | ||
val keyWords: Seq[String] = configuration.get[Seq[String]]("keyWords") | ||
if (!configuration.has("initialDelay") || !configuration.has("interval") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Мы проверяем сразу все поля и, если какого-то нет, падаем с ошибкой общего содержания. Обычно так делать не следует, потому что пользователю (техподдержке) будет не понятно где именно произошла ошибка и придется идти проверять всё. Лучше перенести эти сообщения непосредственно в попытки чтения соответствующего поля и, если его нет, выводить конкретное сообщение |
||
|| !configuration.has("cities") || !configuration.has("keyWords")) | ||
throw new NoSuchFieldException("Configuration doesn't have some of these paths:" + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. В общем случае кидать исключения не ФП стиль, т.к. исключения это сайд эффект. Альтернатива - конструирование объекта Но конкретно тут без конфигурации не получится запустить приложение в принципе (не будет параметров для запуска), так что не сильно критично. Но лучше переместить это в соответствующие места. |
||
" initialDelay, interval, cities, keyWords") | ||
|
||
val initialDelay: Option[String] = configuration.getOptional[String]("initialDelay") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Тут можно сделать одно из двух действий (зависит от задуманной логики):
val initialDelay: String = configuration.getOptional[String]("initialDelay").getOrElse("SomeDefaultValue") 2.при отсутствии значения в конфиге выкинуть исключение: val initialDelay: String = configuration.getOptional[String]("initialDelay").getOrElse(sys.error("Error message")) |
||
val interval: Option[String] = configuration.getOptional[String]("interval") | ||
val cities: Option[Seq[String]] = configuration.getOptional[Seq[String]]("cities") | ||
val keyWords: Option[Seq[String]] = configuration.getOptional[Seq[String]]("keyWords") | ||
|
||
if (initialDelay.isEmpty || interval.isEmpty || cities.isEmpty || keyWords.isEmpty) | ||
throw new ClassCastException("Some of these paths have wrong type: initialDelay, interval, cities, keyWords") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Снова общее сообщение об ошибке. Мало того, что не ясно, какой именно параметр имеет не верный формат, не ясно ещё и какой формат должен быть. Видимо, раз идет проверка на пустоту, должен быть Some. Но тогда следует сразу и читать параметр не как Option'ы |
||
|
||
val initDelay: Try[FiniteDuration] = Try(Duration(initialDelay.get).asInstanceOf[FiniteDuration]) | ||
val interv: Try[FiniteDuration] = Try(Duration(interval.get).asInstanceOf[FiniteDuration]) | ||
|
||
if(initDelay.isFailure || interv.isFailure) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. лучше проверки проводить сразу в момент чтения |
||
throw new ClassCastException("Initial delay or interval have wrong format") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. аналогично общее сообщение без подробностей |
||
|
||
actorSystem.scheduler.scheduleAtFixedRate(initialDelay = Duration(initialDelay).asInstanceOf[FiniteDuration], | ||
interval = Duration(interval).asInstanceOf[FiniteDuration]) { () => | ||
jobAggregatorService.parse(keyWords, cities) | ||
println("Scheduled task executed") | ||
//actorSystem.log.info("Executing something...") | ||
actorSystem.scheduler.scheduleAtFixedRate(initialDelay = initDelay.get, | ||
interval = interv.get) { () => | ||
jobAggregatorService.aggregateData(keyWords.get, cities.get) | ||
Logger("play").info("Scheduled task executed") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Действительно ли это логгирование относится к play'ю? Обычно делают так, что каждый модуль имеет свой собственный логгер и через него логгирует сообщения. Так делают, чтобы в логах можно было быстро найти сообщения от соответствующего компонента. Т.е. тут предлагаю сделать 2 действия:
val logger = Logger("RightName") |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
вместо конкатенации можно использовать интерполяцию: