Understand how services implement business logic and integrate with external systems in Infinitic
Services are the building blocks of your application in Infinitic. They contain the actual business logic, API calls, database operations, and integrations with external systems that workflows orchestrate.
Services can be tagged for routing and metadata for context:
class RoutingWorkflowImpl : Workflow(), RoutingWorkflow { override fun processInRegion(region: String, data: String) { // Create service with tags val regionalService = newService( DataService::class.java, tags = setOf("region:$region"), meta = mapOf( "priority" to "high".toByteArray(), "region" to region.toByteArray() ) ) regionalService.process(data) }}
Tags enable routing specific service calls to specific workers. This is useful for region-specific processing, A/B testing, or canary deployments.
Services support automatic retry and timeout configuration:
import io.infinitic.tasks.WithRetryimport io.infinitic.tasks.WithTimeoutimport java.time.Durationclass ResilientServiceImpl : ResilientService, WithRetry, WithTimeout { override fun getRetryDelay() = 1.0 // 1 second override fun getMaxRetries() = 5 override fun getTimeoutSeconds() = 30.0 // 30 seconds override fun riskyOperation(data: String): Result { // This operation will be retried up to 5 times // with 1 second delay between retries // and will timeout after 30 seconds return externalApi.call(data) }}
Services can be delegated to external systems for human-in-the-loop workflows:
interface ApprovalService { fun requestApproval(requestId: String, details: String): Boolean}// This service can be completed externally via the clientclass ApprovalServiceImpl : ApprovalService { override fun requestApproval(requestId: String, details: String): Boolean { // This task is delegated - it will wait for external completion // The client can complete it using: // client.completeDelegatedTask(serviceName, taskId, result) throw UnsupportedOperationException("This task is delegated") }}
Services are easy to test since they’re plain classes:
import org.junit.jupiter.api.Testimport org.junit.jupiter.api.Assertions.*class PaymentServiceTest { @Test fun `test successful payment`() { val service = PaymentServiceImpl() val result = service.charge("order-123", 99.99) assertNotNull(result.transactionId) assertEquals(PaymentStatus.SUCCESS, result.status) } @Test fun `test payment failure`() { val service = PaymentServiceImpl() assertThrows<PaymentException> { service.charge("invalid-order", -10.0) } }}