Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+1 582новые вакансии за сутки·92 562вакансии открыты сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании7 220
РезюмеAIПодготовкаСтатьи
BoostТарифыBoost
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 402 кандидата открыты к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python17 105
  • Облачные технологии14 068
  • QA вакансии3 460
  • Backend вакансии2 098
  • Инженер данных1 796
  • Продакт-менеджер1 248

Разработка

  • Android1 866
  • iOS1 699
  • Fullstack вакансии979
  • AI вакансии951
  • Frontend вакансии742
  • Mobile вакансии44

По стеку

  • Go8 651
  • Java6 544
  • Node.js2 018
  • .NET1 719
  • Kotlin1 623
  • Rust1 453
  • C#709
  • PHP683
  • C++571

DevOps и инфраструктура

  • Kubernetes7 761
  • DevOps вакансии6 057
  • Linux-инфраструктура5 492
  • Terraform / IaC4 259
  • CI/CD3 240
  • Мониторинг и Observability1 782
  • SRE565
  • Кибербезопасность450

Аналитика и данные

  • Data Scientist1 127
  • Бизнес-аналитик925
  • Аналитик данных845
  • Системный аналитик154

Другие направления

  • Проджект-менеджер611
  • UI/UX дизайн145
  • Ручное тестирование14

По регионам

  • Вакансии в США43 686
  • Вакансии в Европе23 668
  • Вакансии в Канаде4 413
  • Работа в России3 909

По формату

  • Удалённые вакансии73 889
  • Релокация в США43 686
  • Гибридная работа12 392
  • Офисная работа7 088

По уровню

  • Senior вакансии42 236
  • Middle вакансии20 545
  • Junior вакансии6 653

Сейчас нанимают

Все компании
  • Wise190 вакансий
  • Rakuten189 вакансий
  • ASML166 вакансий
  • Grab138 вакансий
  • Celonis39 вакансий
  • Spotify36 вакансий
  • Adyen29 вакансий
  • Infobip28 вакансий
  • Monzo20 вакансий
  • Darktrace16 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме KtorВсе вопросы
KtorSeniorКодинг

Как интегрировать базу данных (например, с Exposed ORM) в приложение Ktor?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

Интеграция Exposed в Ktor требует: HikariCP DataSource, инициализации Database.connect() в модуле, выполнения всех JDBC-операций через newSuspendedTransaction(Dispatchers.IO) и явного закрытия пула при ApplicationStopped.

Зависимости (build.gradle.kts)

dependencies {
    // Ktor
    implementation("io.ktor:ktor-server-core:2.3.12")
    implementation("io.ktor:ktor-server-netty:2.3.12")
    implementation("io.ktor:ktor-server-content-negotiation:2.3.12")
    implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")

    // Exposed
    implementation("org.jetbrains.exposed:exposed-core:0.53.0")
    implementation("org.jetbrains.exposed:exposed-dao:0.53.0")
    implementation("org.jetbrains.exposed:exposed-jdbc:0.53.0")
    implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.53.0")

    // Connection pool + driver
    implementation("com.zaxxer:HikariCP:5.1.0")
    implementation("org.postgresql:postgresql:42.7.3")
}

Почему интеграция требует внимания

Ktor по умолчанию запускает обработчики в coroutine на Dispatchers.Default. Exposed использует JDBC — блокирующий API. Если вызывать transaction { } напрямую без переключения диспетчера, coroutine заблокирует поток event loop и throughput упадёт до числа CPU-ядер. Правильная интеграция требует явного newSuspendedTransaction(Dispatchers.IO) { }.

Определение таблицы и DAO

import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.dao.LongEntity
import org.jetbrains.exposed.dao.LongEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.LongIdTable

object Users : LongIdTable("users") {
    val name = varchar("name", 255)
    val email = varchar("email", 255).uniqueIndex()
    val createdAt = long("created_at").default(0L)
}

class User(id: EntityID<Long>) : LongEntity(id) {
    companion object : LongEntityClass<User>(Users)
    var name by Users.name
    var email by Users.email
    var createdAt by Users.createdAt
}

Инициализация DataSource и Database в модуле

import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import io.ktor.server.application.*
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction

fun Application.configureDatabase() {
    val config = HikariConfig().apply {
        jdbcUrl = environment.config.property("database.url").getString()
        driverClassName = "org.postgresql.Driver"
        username = environment.config.property("database.user").getString()
        password = environment.config.property("database.password").getString()
        maximumPoolSize = 10
        minimumIdle = 2
        connectionTimeout = 30_000
        idleTimeout = 600_000
        maxLifetime = 1_800_000
        isAutoCommit = false      // Exposed управляет транзакциями сам
    }
    val dataSource = HikariDataSource(config)

    // Привязываем DataSource к Exposed
    Database.connect(dataSource)

    // Создаём таблицы (для dev/test; в production — Flyway/Liquibase)
    transaction {
        SchemaUtils.createMissingTablesAndColumns(Users)
    }

    // Закрываем пул при остановке приложения
    environment.monitor.subscribe(ApplicationStopped) {
        dataSource.close()
    }
}

Suspend-транзакции в route-обработчиках

import io.ktor.server.routing.*
import io.ktor.server.response.*
import io.ktor.server.request.*
import io.ktor.http.*
import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import kotlinx.serialization.Serializable

@Serializable
data class CreateUserDto(val name: String, val email: String)

@Serializable
data class UserDto(val id: Long, val name: String, val email: String)

fun Application.userRoutes() {
    routing {
        post("/users") {
            val dto = call.receive<CreateUserDto>()

            // newSuspendedTransaction переключает на Dispatchers.IO
            val user = newSuspendedTransaction(Dispatchers.IO) {
                User.new {
                    name = dto.name
                    email = dto.email
                    createdAt = System.currentTimeMillis()
                }
            }
            call.respond(HttpStatusCode.Created, UserDto(user.id.value, user.name, user.email))
        }

        get("/users/{id}") {
            val id = call.parameters["id"]?.toLongOrNull()
                ?: return@get call.respond(HttpStatusCode.BadRequest)

            val user = newSuspendedTransaction(Dispatchers.IO) {
                User.findById(id)
            } ?: return@get call.respond(HttpStatusCode.NotFound)

            call.respond(UserDto(user.id.value, user.name, user.email))
        }
    }
}

// Сборка модуля
fun Application.module() {
    install(ContentNegotiation) { json() }
    configureDatabase()
    userRoutes()
}

Подводные камни

  • Blocking transaction на Dispatchers.Default. Обычный transaction { } блокирует coroutine-поток; при высокой нагрузке все потоки пула оказываются заняты JDBC-ожиданием, и приложение зависает. Всегда используйте newSuspendedTransaction(Dispatchers.IO).
  • isAutoCommit = false обязателен. HikariCP по умолчанию включает autoCommit; Exposed ожидает, что коммит управляется им самим. Без этой настройки rollback() не работает корректно.
  • Lazy-loading внутри транзакции. В Exposed DAO обращение к связанным объектам (например, user.posts) после закрытия транзакции бросает IllegalStateException: Transaction is not in progress. Всё нужно прочитать внутри newSuspendedTransaction { }.
  • N+1 запросы. Exposed DAO легко провоцирует N+1: если в цикле обращаться к связанным сущностям, каждый доступ порождает новый SELECT. Используйте with(relation) или DSL-запросы с явными JOIN.
  • SchemaUtils в production. SchemaUtils.createMissingTablesAndColumns() не поддерживает миграции (не удаляет лишние колонки, не переименовывает). В production нужны Flyway или Liquibase.
  • Пул соединений и размер. maximumPoolSize нужно согласовать с max_connections в PostgreSQL. По умолчанию у PG 100 соединений; несколько реплик приложения легко исчерпают лимит.
  • Утечка соединения при необработанном исключении. Если coroutine отменяется в середине newSuspendedTransaction, Exposed делает rollback, но соединение возвращается в пул только если HikariCP корректно обрабатывает отмену. Проверяйте метрику hikaricp.connections.active под нагрузкой.
  • Несовместимость версий Exposed. API Exposed менялось между 0.40.x и 0.50.x (переименование методов в DAO, новый синтаксис upsert). Фиксируйте версию явно и проверяйте changelog перед обновлением.

Частые вопросы на собеседовании

  • Какие security-риски возникают в Ktor при CORS, JWT/session auth и обработке multipart-загрузок?
  • Каковы варианты production-деплоя приложения Ktor?
  • Как определять маршруты (routes) в Ktor и как работает вложенная маршрутизация?
  • Что такое plugins (ранее features) в Ktor и как их устанавливать?

Типичные ошибки

  • Путать термин «database exposed» с соседним механизмом Ktor.
  • Не называть границу lifecycle, transaction, thread или request для «database exposed».
  • Игнорировать production-эффекты «database exposed»: latency, SQL shape, memory, security или observability.

Что проверяет интервьюер

  • Попросить объяснить механизм «database exposed» на минимальном примере.
  • Проверить, видит ли кандидат failure mode и диагностику для «database exposed».
  • Уточнить, какие настройки или API меняют «database exposed» в реальном сервисе.

Как вы знаете этот вопрос?

Проверить себя по теме Ktor →

Источники

  • https://ktor.io/docs/server-plugins.html

Связанные темы

Ktorbackend-designimplementationktor