or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdconcurrency.mdcore-effects.mddependency-injection.mderror-handling.mdindex.mdmetrics.mdresource-management.mdservices.mdstm.mdstreams.mdtesting.md

application.mddocs/

0

# Application Framework

1

2

ZIO provides a complete application framework with dependency injection, configuration, and lifecycle management for building production applications with proper resource management and graceful shutdown.

3

4

## Capabilities

5

6

### ZIOApp - Application Entry Point

7

8

The foundational trait for building ZIO applications with custom environments and dependency injection.

9

10

```scala { .api }

11

/**

12

* Base trait for ZIO applications with custom environments

13

*/

14

trait ZIOApp {

15

/** The environment type required by this application */

16

type Environment

17

18

/** Evidence that the environment type has a tag for dependency injection */

19

implicit def environmentTag: EnvironmentTag[Environment]

20

21

/** Layer that provides the application environment from command line args */

22

def bootstrap: ZLayer[ZIOAppArgs, Any, Environment]

23

24

/** Main application logic that runs with the provided environment */

25

def run: ZIO[Environment with ZIOAppArgs with Scope, Any, Any]

26

27

/** Timeout for graceful shutdown (default: infinite) */

28

def gracefulShutdownTimeout: Duration = Duration.Infinity

29

}

30

31

/**

32

* Default ZIO application that requires no custom environment

33

*/

34

abstract class ZIOAppDefault extends ZIOApp {

35

type Environment = Any

36

final def bootstrap: ZLayer[ZIOAppArgs, Any, Any] = ZLayer.empty

37

}

38

39

/**

40

* ZIO application with argument parsing capabilities

41

*/

42

abstract class ZIOAppArgs extends ZIOApp {

43

type Environment = Any

44

final def bootstrap: ZLayer[ZIOAppArgs, Any, Any] = ZLayer.empty

45

46

/** Define command line argument specification */

47

def args: Args[Any]

48

}

49

```

50

51

### Application Helpers

52

53

Utility methods for common application operations and lifecycle management.

54

55

```scala { .api }

56

/**

57

* Get command line arguments within the application

58

*/

59

def getArgs: ZIO[ZIOAppArgs, Nothing, Chunk[String]]

60

61

/**

62

* Exit the application with a specific exit code

63

*/

64

def exit(code: ExitCode): UIO[Unit]

65

66

/**

67

* Run an application programmatically (useful for testing)

68

*/

69

def invoke(args: Chunk[String]): ZIO[Any, Any, Any]

70

71

/**

72

* Combine two applications into one

73

*/

74

def <>(that: ZIOApp): ZIOApp

75

```

76

77

### Application Factory Methods

78

79

Create ZIO applications from effects and layers programmatically.

80

81

```scala { .api }

82

/**

83

* Create a ZIOApp from an effect and bootstrap layer

84

*/

85

def apply[R](

86

run0: ZIO[R with ZIOAppArgs with Scope, Any, Any],

87

bootstrap0: ZLayer[ZIOAppArgs, Any, R]

88

): ZIOApp

89

90

/**

91

* Create a ZIOApp from a simple effect (no custom environment)

92

*/

93

def fromZIO(run0: ZIO[ZIOAppArgs, Any, Any]): ZIOApp

94

95

/**

96

* Proxy class for converting ZIOApp values to runnable applications

97

*/

98

class Proxy(val app: ZIOApp) extends ZIOApp {

99

type Environment = app.Environment

100

def environmentTag = app.environmentTag

101

def bootstrap = app.bootstrap

102

def run = app.run

103

override def gracefulShutdownTimeout = app.gracefulShutdownTimeout

104

}

105

```

106

107

**Usage Examples:**

108

109

```scala

110

import zio._

111

112

// Simple application

113

object SimpleApp extends ZIOAppDefault {

114

def run = for {

115

_ <- Console.printLine("Hello, ZIO!")

116

_ <- Console.printLine("Application completed successfully")

117

} yield ExitCode.success

118

}

119

120

// Application with command line arguments

121

object ArgsApp extends ZIOAppDefault {

122

def run = for {

123

args <- getArgs

124

_ <- Console.printLine(s"Received ${args.length} arguments")

125

_ <- ZIO.foreach(args.zipWithIndex) { case (arg, index) =>

126

Console.printLine(s"Arg[$index]: $arg")

127

}

128

} yield ExitCode.success

129

}

130

131

// Application with custom environment

132

trait UserService {

133

def getUser(id: Long): Task[User]

134

def listUsers(): Task[List[User]]

135

}

136

137

object DatabaseApp extends ZIOApp {

138

type Environment = UserService with Console

139

140

def bootstrap =

141

Console.live ++

142

(DatabaseConfig.live >>> Database.live >>> UserService.live)

143

144

def run = for {

145

userService <- ZIO.service[UserService]

146

users <- userService.listUsers()

147

_ <- Console.printLine(s"Found ${users.length} users")

148

_ <- ZIO.foreach(users)(user => Console.printLine(s"User: ${user.name}"))

149

} yield ExitCode.success

150

}

151

```

152

153

### Application Configuration and Environment

154

155

Patterns for configuring applications and managing environments.

156

157

```scala { .api }

158

// Configuration loading pattern

159

case class AppConfig(

160

serverPort: Int,

161

databaseUrl: String,

162

logLevel: String,

163

enableMetrics: Boolean

164

)

165

166

object AppConfig {

167

// Load from environment variables

168

val fromEnv: Task[AppConfig] = for {

169

port <- System.env("SERVER_PORT").map(_.getOrElse("8080")).map(_.toInt)

170

dbUrl <- System.env("DATABASE_URL").someOrFail(new RuntimeException("DATABASE_URL required"))

171

logLevel <- System.env("LOG_LEVEL").map(_.getOrElse("INFO"))

172

metrics <- System.env("ENABLE_METRICS").map(_.getOrElse("false")).map(_.toBoolean)

173

} yield AppConfig(port, dbUrl, logLevel, metrics)

174

175

// Layer for dependency injection

176

val live: TaskLayer[AppConfig] = ZLayer.fromZIO(fromEnv)

177

}

178

179

// Service layer pattern

180

trait DatabaseService {

181

def connect(): Task[Unit]

182

def disconnect(): Task[Unit]

183

def query(sql: String): Task[List[Map[String, Any]]]

184

}

185

186

object DatabaseService {

187

val live: RLayer[AppConfig, DatabaseService] = ZLayer {

188

for {

189

config <- ZIO.service[AppConfig]

190

} yield DatabaseServiceImpl(config.databaseUrl)

191

}

192

}

193

194

// HTTP server layer pattern

195

trait HttpServer {

196

def start(): Task[Unit]

197

def stop(): Task[Unit]

198

}

199

200

object HttpServer {

201

val live: RLayer[AppConfig with UserService, HttpServer] = ZLayer {

202

for {

203

config <- ZIO.service[AppConfig]

204

userService <- ZIO.service[UserService]

205

} yield HttpServerImpl(config.serverPort, userService)

206

}

207

}

208

```

209

210

### Complete Application Examples

211

212

Full application examples demonstrating various patterns and configurations.

213

214

```scala { .api }

215

// Microservice application

216

object MicroserviceApp extends ZIOApp {

217

type Environment = AppConfig with DatabaseService with HttpServer with Console

218

219

def bootstrap =

220

AppConfig.live ++

221

Console.live ++

222

(AppConfig.live >>> DatabaseService.live) ++

223

(AppConfig.live ++ UserService.live >>> HttpServer.live)

224

225

def run = for {

226

config <- ZIO.service[AppConfig]

227

db <- ZIO.service[DatabaseService]

228

server <- ZIO.service[HttpServer]

229

230

_ <- Console.printLine(s"Starting microservice on port ${config.serverPort}")

231

_ <- db.connect()

232

_ <- server.start()

233

_ <- Console.printLine("Microservice started successfully")

234

235

// Run until interrupted

236

_ <- ZIO.never

237

238

} yield ExitCode.success

239

}

240

241

// CLI application with subcommands

242

sealed trait Command

243

case class ListUsers(limit: Int) extends Command

244

case class CreateUser(name: String, email: String) extends Command

245

case class DeleteUser(id: Long) extends Command

246

247

object CliApp extends ZIOApp {

248

type Environment = UserService with Console

249

250

def bootstrap =

251

Console.live ++

252

(DatabaseConfig.live >>> Database.live >>> UserService.live)

253

254

def run = for {

255

args <- getArgs

256

command <- parseCommand(args)

257

_ <- executeCommand(command)

258

} yield ExitCode.success

259

260

private def parseCommand(args: Chunk[String]): Task[Command] = {

261

args.toList match {

262

case "list" :: limit :: Nil =>

263

ZIO.succeed(ListUsers(limit.toInt))

264

case "create" :: name :: email :: Nil =>

265

ZIO.succeed(CreateUser(name, email))

266

case "delete" :: id :: Nil =>

267

ZIO.succeed(DeleteUser(id.toLong))

268

case _ =>

269

ZIO.fail(new IllegalArgumentException("Invalid command"))

270

}

271

}

272

273

private def executeCommand(command: Command): ZIO[UserService with Console, Throwable, Unit] = {

274

command match {

275

case ListUsers(limit) =>

276

for {

277

users <- ZIO.service[UserService].flatMap(_.listUsers(limit))

278

_ <- ZIO.foreach(users)(user => Console.printLine(s"${user.id}: ${user.name}"))

279

} yield ()

280

281

case CreateUser(name, email) =>

282

for {

283

user <- ZIO.service[UserService].flatMap(_.createUser(name, email))

284

_ <- Console.printLine(s"Created user: ${user.id}")

285

} yield ()

286

287

case DeleteUser(id) =>

288

for {

289

_ <- ZIO.service[UserService].flatMap(_.deleteUser(id))

290

_ <- Console.printLine(s"Deleted user: $id")

291

} yield ()

292

}

293

}

294

}

295

296

// Batch processing application

297

object BatchProcessor extends ZIOApp {

298

type Environment = AppConfig with DatabaseService with Console

299

300

def bootstrap =

301

AppConfig.live ++

302

Console.live ++

303

(AppConfig.live >>> DatabaseService.live)

304

305

def run = for {

306

config <- ZIO.service[AppConfig]

307

_ <- Console.printLine("Starting batch processing job")

308

309

// Process in batches

310

_ <- processInBatches(batchSize = 1000)

311

312

_ <- Console.printLine("Batch processing completed")

313

} yield ExitCode.success

314

315

private def processInBatches(batchSize: Int): ZIO[DatabaseService with Console, Throwable, Unit] = {

316

def processBatch(offset: Int): ZIO[DatabaseService with Console, Throwable, Boolean] = {

317

for {

318

db <- ZIO.service[DatabaseService]

319

batch <- db.query(s"SELECT * FROM records LIMIT $batchSize OFFSET $offset")

320

321

_ <- ZIO.when(batch.nonEmpty) {

322

Console.printLine(s"Processing batch of ${batch.length} records at offset $offset") *>

323

ZIO.foreach(batch)(processRecord) *>

324

ZIO.sleep(100.millis) // Rate limiting

325

}

326

} yield batch.nonEmpty

327

}

328

329

def loop(offset: Int): ZIO[DatabaseService with Console, Throwable, Unit] = {

330

processBatch(offset).flatMap { hasMore =>

331

if (hasMore) loop(offset + batchSize)

332

else ZIO.unit

333

}

334

}

335

336

loop(0)

337

}

338

339

private def processRecord(record: Map[String, Any]): Task[Unit] = {

340

// Process individual record

341

ZIO.succeed(())

342

}

343

}

344

345

// Testing applications

346

object TestableApp {

347

def make(userService: UserService): ZIOApp = {

348

ZIOApp.fromZIO {

349

for {

350

users <- userService.listUsers()

351

_ <- Console.printLine(s"Found ${users.length} users")

352

} yield ExitCode.success

353

}

354

}

355

}

356

357

// Application testing

358

val testApp = for {

359

mockUserService <- ZIO.succeed(MockUserService(List(User(1, "Alice"), User(2, "Bob"))))

360

app = TestableApp.make(mockUserService)

361

result <- app.invoke(Chunk.empty)

362

} yield result

363

```

364

365

### Application Lifecycle and Shutdown

366

367

Managing application lifecycle, graceful shutdown, and resource cleanup.

368

369

```scala { .api }

370

// Graceful shutdown pattern

371

object GracefulApp extends ZIOApp {

372

type Environment = HttpServer with DatabaseService with Console

373

374

override def gracefulShutdownTimeout = 30.seconds

375

376

def bootstrap =

377

Console.live ++

378

DatabaseService.live ++

379

HttpServer.live

380

381

def run = ZIO.scoped {

382

for {

383

server <- ZIO.service[HttpServer]

384

db <- ZIO.service[DatabaseService]

385

386

// Add shutdown hooks

387

_ <- Scope.addFinalizerExit { exit =>

388

for {

389

_ <- Console.printLine("Shutting down gracefully...")

390

_ <- server.stop().timeout(10.seconds).ignore

391

_ <- db.disconnect().timeout(5.seconds).ignore

392

_ <- Console.printLine("Shutdown complete")

393

} yield ()

394

}

395

396

// Start services

397

_ <- db.connect()

398

_ <- server.start()

399

_ <- Console.printLine("Application started")

400

401

// Run until interrupted

402

_ <- ZIO.never

403

404

} yield ExitCode.success

405

}

406

}

407

408

// Health check and monitoring

409

trait HealthCheck {

410

def check(): Task[HealthStatus]

411

}

412

413

case class HealthStatus(service: String, healthy: Boolean, message: Option[String])

414

415

object HealthCheckApp extends ZIOApp {

416

type Environment = List[HealthCheck] with Console

417

418

def bootstrap =

419

Console.live ++

420

ZLayer.succeed(List(

421

DatabaseHealthCheck(),

422

HttpHealthCheck(),

423

DiskSpaceHealthCheck()

424

))

425

426

def run = for {

427

_ <- performHealthChecks.repeat(Schedule.fixed(30.seconds))

428

} yield ExitCode.success

429

430

private def performHealthChecks: ZIO[List[HealthCheck] with Console, Throwable, Unit] = {

431

for {

432

healthChecks <- ZIO.service[List[HealthCheck]]

433

results <- ZIO.foreachPar(healthChecks)(_.check())

434

435

healthy = results.forall(_.healthy)

436

_ <- Console.printLine(s"Health check: ${if (healthy) "HEALTHY" else "UNHEALTHY"}")

437

438

_ <- ZIO.foreach(results.filter(!_.healthy)) { status =>

439

Console.printLineError(s"${status.service}: ${status.message.getOrElse("Unknown error")}")

440

}

441

} yield ()

442

}

443

}

444

445

// Multi-environment application

446

object MultiEnvApp extends ZIOApp {

447

type Environment = AppConfig with DatabaseService with Console

448

449

def bootstrap = {

450

val env = System.env("APP_ENV").map(_.getOrElse("development"))

451

452

ZLayer.fromZIO(env).flatMap {

453

case "production" => productionLayers

454

case "staging" => stagingLayers

455

case "development" => developmentLayers

456

case "test" => testLayers

457

case unknown => ZLayer.fail(new RuntimeException(s"Unknown environment: $unknown"))

458

}

459

}

460

461

private val productionLayers =

462

Console.live ++

463

ProductionConfig.live ++

464

(ProductionConfig.live >>> DatabaseService.live)

465

466

private val developmentLayers =

467

Console.live ++

468

DevelopmentConfig.live ++

469

(DevelopmentConfig.live >>> DatabaseService.live)

470

471

// ... other environment layers

472

473

def run = for {

474

config <- ZIO.service[AppConfig]

475

_ <- Console.printLine(s"Running in environment: ${config.environment}")

476

_ <- mainApplicationLogic

477

} yield ExitCode.success

478

}

479

```