Course outline

Spring Boot / Advanced: observability and resilient releases / Lesson 16

Packaging, deployment, and graceful shutdown

Treat the deployable artifact, runtime, configuration, readiness, migration, and shutdown sequence as one versioned service contract.

About 5 min readContent reviewed
On this page

Lesson goals

  • Explain executable packaging and managed build versions.
  • Separate build-time assets from deployment secrets.
  • Plan readiness and graceful drain with bounded resources.

Deploy a known artifact instead of an incidental workspace

A release should identify source revision, resolved dependencies, compiler target, test evidence, artifact hash, runtime requirements, and configuration contract. An application that works through an IDE may rely on undeclared paths or development settings. Build an immutable deployable artifact through a reproducible process rather than modifying application classes or dependencies ad hoc on a running host.

The pinned Boot3.5.16 line requires a compatible Java and build-tool environment. An installed Gradle9.x does not automatically satisfy the documented3.5 Gradle support range. Use a compatible controlled toolchain or reviewed wrapper in a real project; the course does not install global/project dependencies or run packaging that would initialize services. Syntax examples are labeled separately from actual artifact verification.

Read packaging configuration as a proposed build contract

The Maven fragment declares the Boot packaging plugin under the pinned parent's management and enables layers. It is not a whole pom, a built jar, or a performed image build. Executable packaging arranges application classes, dependencies, and launcher conventions; it does not make a classpath/runtime mismatch disappear. Verify the resulting artifact with the intended Java runtime and supported launch approach in an authorized environment.

Layering can improve image/build reuse but is not proof of a smaller runtime footprint or faster requests. Native-image packaging has its own compiler, reachability, reflection/resource, and compatibility requirements and is not simply the same JVM jar with a different filename. No native compiler, container builder, or deployment service is provisioned here.

xml Illustrative packaging fragment under the pinned parent
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <layers><enabled>true</enabled></layers>
      </configuration>
    </plugin>
  </plugins>
</build>

This XML fragment is syntax-parseable but requires the rest of the project. No jar, image, or native executable was built.

Keep the same artifact under approved external policy

External configuration lets one artifact run with deliberately different approved policies, but precedence and validation still need tests. Keep credentials and private endpoints out of source and packaged fixtures. A profile name does not protect a service or prove that the correct identity provider/database is selected. Validate effective non-secret configuration and supported resource limits before accepting traffic.

Database schema evolution must be compatible with both old and new consumers during a rolling change, or the rollout must coordinate their access. A rollback of application code does not automatically reverse a committed database migration or external side effect. Define a tested recovery/forward-fix plan and the conditions under which the older artifact remains safe to run.

Coordinate drain, readiness, and shutdown budgets

The YAML states graceful shutdown and a per-phase lifecycle timeout explicitly. It is an illustrative policy, not an observed process drain. The infrastructure's termination grace, routing removal, request deadlines, executor shutdown, and resource cleanup must agree. A lifecycle timeout is not a guarantee that every arbitrary task or remote call will finish within the total service termination budget.

Stop admitting new business work, preserve truthful status for in-flight operations, and close owned resources according to lifecycle. Durable jobs need recovery on another run; local callbacks or scheduled tasks may otherwise disappear. Actuator readiness and the main serving path must reflect intended routing behavior. Do not simulate deployment by launching a listener or sending termination/admin commands to a configured process.

yaml Illustrative drain-related application settings
server:
  shutdown: graceful
spring:
  lifecycle:
    timeout-per-shutdown-phase: 20s
management:
  endpoint:
    health:
      probes:
        enabled: true
        add-additional-paths: true

The configuration declares intent only. Platform grace periods, in-flight operations, and actual shutdown behavior require controlled integration evidence.

Verify release and recovery as separate capabilities

A release gate should include contract tests, security denials, configuration validation, schema compatibility, bounded startup, health semantics, and clean shutdown in an approved isolated environment. Keep image/artifact identity and rollback criteria reviewable. A passing syntax parser or dependency-free model is useful but cannot certify a packaged Spring application or production infrastructure.

Record what was actually built and run, and keep failed checks visible. Never embed real credentials in a smoke fixture or point a test at a configured datasource because a release deadline is near. The same rigor applies to recovery drills. An application release is complete when the intended service, its data contract, and its failure/recovery paths are verified at their real boundaries.

Common errors and fixes

The packaged application differs from the IDE run

Why it happens
Artifact dependencies or configuration were not reproducible.
How to fix it
Inspect the actual built artifact and runtime contract.
Prevent it next time
Test the deployable form in isolation.

Application rollback failed after a schema change

Why it happens
Code and data compatibility were treated independently.
How to fix it
Use a reviewed compatible migration/recovery plan.
Prevent it next time
Test old/new consumer coexistence.

Graceful shutdown dropped untracked work

Why it happens
Admission, lifecycle budgets, or durable recovery were undefined.
How to fix it
Coordinate drain and persist recovery identity where required.
Prevent it next time
Test interrupted and in-flight operations.

Check your understanding

1. Does a20s per-phase timeout guarantee the whole deployment terminates correctly in20s?

Show worked solution

No. Platform grace periods, several lifecycle phases, request/client deadlines, executor cleanup, and durability/recovery all matter. Define the end-to-end budget and verify it in a controlled environment rather than equating one property with complete operational success.

2. Why can an older jar be unsafe after a successful new-schema rollout?

Show worked solution

Its queries, assumptions, constraints, or feature support may no longer match the database. Application-file rollback is not data rollback. Plan compatibility, forward repair, or tested restoration explicitly, and keep external side effects outside claims a database backup cannot satisfy.

Key takeaways

  • The artifact, runtime, configuration, and data schema form one release contract.
  • Graceful drain requires coordinated budgets and truthful in-flight state.
  • Recovery evidence is independent of build or syntax success.

Official references