Сдвиг контекста - это просто кошачья обертка над ExecutionContext
. Вы можете создать его явно как указано в документах:
implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
Обычно вы создаете один сдвиг контекста в точке входа вашего приложения (возможно, в основном методе).
Если ваше приложение использует IOApp
from cats-effect, это уже будет неявно для contextShift в области видимости. Он будет использовать контекст выполнения, который будет иметь количество потоков, равное доступным процессорам вашего компьютера.
Если вы хотите использовать созданный contextShift «глубже» внутри вашего приложения, вы можете передать его как неявный параметр:
def doSomething(implicit cs: ContextShift[IO]): IO[Unit] = ???
Итак, чтобы ваш код работал, вам необходимо убедиться, что конструктор вызовов метода или класса UserSvcServlet
имеет неявное значение для contextShift: (implicit cs: ContextShift[IO])
.
Вы также можете указать это в отдельном объекте:
object AppContextShift {
implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
implicit val t: Timer[IO] = IO.timer(ExecutionContext.global) //you will probably also need timer eventually
}
Затем вы можете импортировать его, когда требуется contextShift:
import AppContextShift._
Кстати, использование глобального контекста выполнения для Blocker не подходит идея. Blocked используется для блокировки операций, и его использование с ExecutionContext.global
может привести к нехватке потоков в вашем приложении.
Наиболее распространенный подход - использовать блокировщик, созданный из кэшированного пула потоков:
Blocker.liftExecutorService(Executors.newCachedThreadPool())