skip to content

A team runs a Spring Cloud Config Server backed by a Git repository, serving configuration to 40 microservices. Walk through how a configuration change made in a git commit reaches a running service, and what has to happen for services to pick up the change without a restart.

level: middleimportance: must knowfreq 70%

answer

  1. bootstrap-time HTTP pull
  2. @RefreshScope + /actuator/refresh
  3. Spring Cloud Bus broadcasts refresh
  4. git commit alone doesn't push
  5. canary config changes

basics

~20 s

The config values live in a separate git repo. A central 'config server' reads that repo and hands values to each service on request. Editing the repo alone doesn't reach running services — they either re-fetch on next restart or must be explicitly told to refresh live.

solid answer

~30 s

Spring Cloud Config Server exposes an HTTP API backed by a git repo; each client service, on startup, calls the config server before its Spring context fully initializes, pulling its properties so config is resolved before beans are created. A git commit alone doesn't reach running instances — the server just serves whatever's at the branch tip on the next request. To apply changes live, you either hit each instance's `/actuator/refresh` endpoint (re-binds `@RefreshScope` beans) or, at scale, wire a git webhook to Spring Cloud Bus, which broadcasts a refresh event over a message broker to every subscribed instance at once.

go deeper

for a junior

Should know a config server centralizes config in one place fetched over HTTP; doesn't need refresh internals.

for a middle

Should explain the bootstrap-time pull, that a plain commit doesn't push to running instances, and name @RefreshScope or actuator refresh as the mechanism for live updates.

for a senior

Should discuss Spring Cloud Bus for broadcasting refresh at scale, the fail-fast startup dependency risk, and canarying config changes to limit blast radius.

for a principal

Should reason about the config server as a platform dependency with its own availability requirements, and design staged rollout and rollback strategy for config independent of code deploys.

## The moving pieces **Spring Cloud Config Server** is a stand-alone Spring Boot application with a git (or vault, native filesystem, or JDBC) backend. It exposes REST endpoints such as `/{application}/{profile}/{label}` that return a merged property set. Each microservice acts as a **config client**: on bootstrap, before its `ApplicationContext` is fully built, `spring.config.import=configserver:` (or the older `bootstrap.yml`) tells the client to - call the config server, - fetch its named application-plus-profile properties, - and layer them on top of the local `application.yml`. This is a one-time HTTP call at startup by default, not a persistent connection. ## What a git commit actually reaches Committing to git changes what the server will hand out on the NEXT request; it doesn't push anything to already-running instances, because their initial fetch already happened and those values are cached inside the Spring `Environment`. To make a running instance pick up new values, the beans that read the property need `@RefreshScope`, which wraps them in a lazy proxy that gets recreated on a refresh event, and you need to trigger that event: 1. **Manually**, via each instance's `/actuator/refresh` — impractical across 40 services times N replicas. 2. **Via Spring Cloud Bus**, where a git webhook (or a manual POST to `/actuator/bus-refresh`) publishes a refresh event onto a shared broker topic (RabbitMQ or Kafka) that every subscribed instance listens to, refreshing nearly simultaneously. ## Why it exists This exists to solve a real coordination problem: with 40 services each shipping its own baked-in `application.yml`, changing one shared value (say a downstream API timeout used by ten of them) would mean ten separate PRs, builds, and redeploys. A config server centralizes that into one commit and one source of truth, versioned and diffable in git (giving audit history and rollback via `git revert`), served consistently per environment through branches or labels, decoupling "change a config value" from "run a full deploy pipeline." ## The trade-offs The trade-offs cut both ways. - **A new single point of failure and a new startup dependency.** Centralizing introduces both: if the config server is unreachable when a service boots, that service can't start unless configured with `fail-fast=false` plus a local fallback, in which case it might start with stale or default config while still reporting healthy. - **`@RefreshScope` has real cost too.** It wraps beans in proxies, which subtly interacts with things like `@Scheduled` methods or beans holding expensive state that don't expect to be silently swapped mid-run. - **Bus-based refresh is also only eventually consistent.** During a rollout, some instances hold new config and some hold old, so config changes have to tolerate that window rather than assume atomicity. ## Failure modes in production In production, a classic incident is a bad property value — an invalid connection-pool size, say — committed and pushed via bus-refresh to all instances at once, causing all 40 services to fail simultaneously instead of just one: the same mechanism that makes propagation fast also makes a bad change's blast radius platform-wide, which is why teams **canary** config changes to one instance or environment before broadcasting. Another common failure is the config server itself becoming a **bottleneck**: every new pod calls it at startup, so a mass restart or autoscaling event can produce a thundering herd that overwhelms the server or its git backend, pushing production setups toward caching layers or horizontally scaled config servers fronted by a git mirror. ## A representative real setup A representative real setup pairs Spring Cloud Config Server, Spring Cloud Bus, and RabbitMQ so that a merge to a config repo's `payment-service.yml` triggers a webhook, the config server publishes a bus event, and every running `payment-service` pod re-resolves its `@RefreshScope` beans — say a `RestTemplate` timeout — within seconds, with no redeploy and a fully auditable git history behind the change.

  • What does @RefreshScope actually do under the hood, and what's a subtle danger of applying it broadly?
    It wraps the bean in a scoped proxy so that on a refresh event the proxy discards the underlying instance and lazily recreates it with the new property values on next access — the bean itself isn't literally mutated in place. The danger is that beans holding stateful internals, like open connections, in-flight caches, or scheduled timers, can be silently swapped mid-operation, causing subtle bugs such as a scheduled job losing its state or a connection pool being torn down while requests are in flight.
  • What happens to a service if the config server is completely down when a new pod tries to start?
    By default, Spring Cloud Config clients fail fast and refuse to start if they can't reach the config server, protecting against silently running with wrong or default config but turning a config-server outage into a platform-wide deploy or scale-up outage. Teams mitigate this with `spring.cloud.config.fail-fast=false` plus sane local defaults, or by running the config server itself as a highly-available, independently deployable service with its own health checks and redundancy.
  • How would you safely roll out a risky config change across 40 services without an all-at-once blast radius?
    Canary the change: apply it first to one service instance or one environment, verify metrics, then progressively widen it — either by controlling which git branch or label each tier tracks, or by targeting bus-refresh to specific destination services rather than broadcasting a refresh event to everyone simultaneously.

Like a company intranet policy page: editing the page doesn't automatically walk into every employee's office and update their printed copy — someone has to either hand out flyers (manual refresh) or ring the office-wide PA system (bus refresh) to get everyone to reprint at once.

saying these in an interview costs you the question

  • Believes a git commit alone updates running services
  • Doesn't know @RefreshScope or an equivalent is required for live updates
  • Proposes restarting all 40 services for every config tweak with no faster path
  • Unaware that config-server unavailability can block new pods from starting
  • No mention of canarying or staged rollout for risky config pushes

context