A service interface is a standard Java or Kotlin interface:
interface EmailService { fun sendEmail(to: String, subject: String, body: String): Boolean fun sendBulkEmails(emails: List<EmailData>): Map<String, Boolean>}data class EmailData( val to: String, val subject: String, val body: String)
Services can accept dependencies through their constructor:
class EmailServiceImpl( private val emailProvider: EmailProvider, private val logger: Logger, private val config: EmailConfig) : EmailService { override fun sendEmail(to: String, subject: String, body: String): Boolean { logger.info("Sending email to $to") return emailProvider.send( to = to, subject = subject, body = body, from = config.defaultSender ) }}
import io.infinitic.annotations.Timeoutimport io.infinitic.tasks.WithTimeoutclass ThirtySecondTimeout : WithTimeout { override fun getTimeoutSeconds(): Double = 30.0}class EmailServiceImpl : EmailService { @Timeout(ThirtySecondTimeout::class) override fun sendEmail(to: String, subject: String, body: String): Boolean { // Will timeout after 30 seconds }}
You can also specify a grace period:
class TimeoutWithGrace : WithTimeout { override fun getTimeoutSeconds(): Double = 30.0 // Allow 5 seconds to clean up after timeout override fun getGracePeriodAfterTimeoutSeconds(): Double = 5.0}
Process multiple tasks together for improved performance:
import io.infinitic.annotations.Batchclass EmailServiceImpl : EmailService { // Regular method signature override fun sendEmail(to: String, subject: String, body: String): Boolean { throw NotImplementedError("Use batch method") } // Batch implementation receives a map of task IDs to inputs @Batch fun sendEmail(batch: Map<String, Input>): Map<String, Boolean> { // Process all emails in a single operation return batch.mapValues { (taskId, input) -> emailProvider.send(input.to, input.subject, input.body) } } data class Input(val to: String, val subject: String, val body: String)}
import io.infinitic.tasks.Taskimport org.junit.jupiter.api.Testimport kotlin.test.assertEqualsclass EmailServiceTest { @Test fun `test sendEmail`() { val service = EmailServiceImpl( emailProvider = MockEmailProvider(), logger = MockLogger(), config = TestEmailConfig() ) val result = service.sendEmail( to = "[email protected]", subject = "Test", body = "Test body" ) assertEquals(true, result) } @Test fun `test with task context`() { // Set up task context for testing val mockContext = MockTaskContext() Task.setContext(mockContext) val service = EmailServiceImpl() service.sendEmail("[email protected]", "Test", "Body") // Verify task context was used correctly }}
Use KDoc or JavaDoc to document non-obvious behavior:
interface EmailService { /** * Sends an email to the specified recipient. * * @param to Recipient email address * @param subject Email subject line * @param body Email body (supports HTML) * @return EmailResult containing success status and message ID * @throws InvalidEmailException if the email address is malformed */ fun sendEmail(to: String, subject: String, body: String): EmailResult}