Metadata-Version: 2.4
Name: flask-nacos
Version: 1.0.2
Summary: A Flask extension for integrating with Nacos service discovery and configuration center.
Project-URL: Homepage, https://github.com/pumpkin-nbc/Flask-Nacos
Project-URL: Repository, https://github.com/pumpkin-nbc/Flask-Nacos
Project-URL: Documentation, https://github.com/pumpkin-nbc/Flask-Nacos/tree/master/docs
Project-URL: Issues, https://github.com/pumpkin-nbc/Flask-Nacos/issues
Project-URL: Changelog, https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/CHANGELOG.md
Project-URL: Security, https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/SECURITY.md
Author-email: Pumpkin <a760329881@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: configuration,flask,microservices,nacos,service-discovery
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Flask
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: flask<4.0,>=1.0
Requires-Dist: nacos-sdk-python<3.0.0,>=2.0.0
Provides-Extra: dev
Requires-Dist: build>=1.2.0; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.5.0; extra == 'dev'
Requires-Dist: twine>=5.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# Flask-Nacos

English | [简体中文](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/README.zh-CN.md)

`flask-nacos` is a Flask extension that integrates Flask applications with
[Nacos](https://nacos.io/), providing service registration, deregistration,
service discovery, and configuration-center access. It follows the conventions
of common Flask extensions such as `Flask-SQLAlchemy` and `Flask-Redis`.

## New users start here

- **New to Python or Flask-Nacos:** follow the
  [beginner quickstart](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/quickstart.md). It first runs Flask without Nacos,
  then adds registration, config reads, and discovery one step at a time.
- **Ready to integrate a real project:** use the
  [complete integration example](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/complete-example.md) with factory mode and
  environment-based configuration.
- **Preparing for production:** read [Production](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/production.md) for
  Gunicorn, containers, multiple workers, and security.

You do not need to read every config key or API page first. Start by copying the
quickstart exactly as written.

## Features

- Simple `FlaskNacos(app)` and application-factory `init_app(app)` styles.
- Nacos client initialization from `app.config`, with namespace and
  username/password authentication.
- Automatic and manual service registration.
- Automatic (via `atexit`) and manual service deregistration.
- Service discovery: list instances and pick one healthy instance.
- Configuration-center read support (`get_config`).
- Configurable fail-fast behavior with a dedicated exception hierarchy.
- Standard `logging` integration that never logs secrets.
- Unified retry for Nacos operations, an optional health-check route, and a
  `get_status()` runtime inspector (0.3.0).
- Per-process registration lifecycle, safe deregistration, instance
  normalization, and `first`/`random`/`weight` discovery strategies (0.4.0).
- Full type hints with `py.typed` (PEP 561), plus ruff/mypy/pytest/coverage
  configuration and CI (0.5.0).
- Release tooling: version-consistency, package-content, and sensitive-info
  check scripts, a one-shot `release_check.sh`, expanded CI checks, and a
  manual TestPyPI/PyPI release workflow (0.6.0).
- Full documentation set under [`docs/`](https://github.com/pumpkin-nbc/Flask-Nacos/tree/master/docs), enhanced examples, a local
  Nacos Docker Compose file, and a documentation-consistency check (0.7.0).
- Broad compatibility: Python 3.8-3.13 and Flask `>=1.0,<4.0` (1.x/2.x/3.x),
  tolerant handling of different Nacos SDK response shapes, a Python-3.8
  compatibility checker, and a Python x Flask CI matrix (0.8.0).
- Release Candidate preparation: frozen public API with an API-snapshot check,
  backward-compatibility tests, an examples validator, a package smoke test, and
  a 1.0.0 acceptance checklist (0.9.0).
- First stable release: the public API is declared stable for the 1.0 series and
  is verified by an API-snapshot check and backward-compatibility tests (1.0.0).

## Stable release

`1.0.0` is the first stable release of Flask-Nacos, intended for PyPI. The public
API is stable for the 1.0 series: method names, existing parameters, and return
contracts will not change without a deprecation cycle, and any new parameters
will be added with defaults so existing code keeps working.

- `get_config()` returns the raw Nacos config content only; it does not perform
  YAML, JSON, or dict parsing.
- This version does not provide `get_config_as_dict()`.
- This version does not provide `load_config_to_flask()`.
- Nacos configuration is never written into Flask `app.config` automatically.
- See the full pre-release verification in
  [docs/1.0-checklist.md](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/1.0-checklist.md).

## Compatibility

- Python: 3.8 - 3.13.
- Flask: `>=1.0, <4.0` (Flask 1.x, 2.x, and 3.x).
- Nacos: server 2.x with the synchronous `nacos-sdk-python` client.
- Service discovery tolerates different SDK response shapes (plain list,
  `hosts`/`instances`, or a nested `data` wrapper) and both camelCase and
  snake_case instance fields.

See [Compatibility](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/compatibility.md) for details.

## Installation

```bash
pip install flask-nacos
```

For local development (tests, linting, type checking, building):

```bash
pip install -e ".[dev]"
```

## Quick Start

Follow the [beginner quickstart](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/quickstart.md). It includes Windows
PowerShell and macOS/Linux commands, a complete copy-ready `app.py`, expected
results for every step, and common-error fixes.

## Documentation

Full documentation lives under [`docs/`](https://github.com/pumpkin-nbc/Flask-Nacos/tree/master/docs):

- [Quickstart](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/quickstart.md) - beginner path from Python setup through all core features.
- [Complete Example](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/complete-example.md) - end-to-end factory integration.
- [Configuration](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/configuration.md) - every config key, grouped.
- [API Reference](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/api-reference.md) - public methods and error behavior.
- [Service Registration](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/service-registration.md) - register/deregister.
- [Service Discovery](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/service-discovery.md) - listing and strategies.
- [Health Check](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/health-check.md) - the optional health route.
- [Production](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/production.md) - Gunicorn/uWSGI/Docker deployment.
- [Troubleshooting](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/troubleshooting.md) - common issues and fixes.
- [Compatibility](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/compatibility.md) - supported Python/Flask/Nacos versions.
- [1.0.0 Checklist](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/1.0-checklist.md) - release-candidate acceptance list.
- [Release Guide](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/release.md) - publishing to TestPyPI/PyPI.
- [Changelog](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/changelog.md) - links to the full changelog.

## Flask Standard Mode

```python
from flask import Flask
from flask_nacos import FlaskNacos

app = Flask(__name__)
app.config.from_object("config.Config")

nacos = FlaskNacos(app)
```

## Flask Factory Mode

```python
from flask import Flask
from flask_nacos import FlaskNacos

nacos = FlaskNacos()

def create_app():
    app = Flask(__name__)
    app.config.from_object("config.Config")
    nacos.init_app(app)
    return app
```

If your project initializes SQLAlchemy, Redis, and other extensions through a
shared `app/extensions.py`, see the [existing extension registry pattern](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/complete-example.md#integrate-with-an-existing-flask-extension-registry).

## Service Registration

When `NACOS_REGISTER_ENABLED`, `NACOS_AUTO_REGISTER`, and
`NACOS_AUTO_REGISTER_ON_INIT` are all `True`, registration settings are
validated and the service is registered synchronously during `init_app(app)`.
You can also register manually. `NACOS_REGISTER_ENABLED` only controls
init-time automatic registration; it does not disable an explicit
`register_instance()` call:

```python
nacos.register_instance()
```

### Registration Parameter Rules

The following are validated before an instance is registered. Invalid values
follow the `NACOS_FAIL_FAST` rule (see [Exception Handling](#exception-handling)):

- `NACOS_SERVICE_NAME` - required, must be a non-empty, non-whitespace string.
- `NACOS_SERVICE_PORT` - required, must be an integer in the range `1-65535`.
- `NACOS_SERVICE_WEIGHT` - must be a finite number greater than `0`.
- `NACOS_SERVICE_METADATA` - must be a `dict`.
- `NACOS_SERVICE_EPHEMERAL` - must be a `bool`.
- `NACOS_SERVICE_HEARTBEAT_INTERVAL` - finite number greater than `0` (seconds).

Ephemeral instances use SDK heartbeats every `5.0` seconds by default. The
initial healthy flag does not replace heartbeat renewal; persistent instances
do not receive a heartbeat interval.

When `NACOS_LOG_ENABLED=True`, every temporary-instance heartbeat emits a
sanitized status record: success at `INFO` and failure at `ERROR`. Records
include only service, IP, port, group, and (on failure) the exception type.
SDK responses, exception messages, credentials, tokens, signatures, metadata,
and configuration content are never logged. The SDK heartbeat thread keeps
retrying after a failed request.

Registration and deregistration succeed only when SDK 2.x explicitly returns
`True`. A `False` result follows the normal retry and `NACOS_FAIL_FAST` flow and
does not update the extension's registered state.

Registration is idempotent: calling `register_instance()` multiple times on the
same extension instance registers only once (subsequent calls are no-ops).

### Service IP Auto-detection

If `NACOS_SERVICE_IP` is not provided, the extension attempts to detect the
local outbound IP via the `get_local_ip()` helper. If detection fails, the
behavior follows the `NACOS_FAIL_FAST` rule.

> Production recommendation: explicitly configure `NACOS_SERVICE_IP` rather than
> relying on auto-detection. In containers, multi-NIC hosts, or behind NAT the
> auto-detected address may not be the one you want other services to reach.

## Service Deregistration

When `NACOS_AUTO_DEREGISTER` is `True`, an instance successfully registered by
this extension is deregistered on process exit via `atexit`. You can also
deregister manually:

```python
nacos.deregister_instance()
```

Deregistration is idempotent: once an instance has been deregistered, further
`deregister_instance()` calls are no-ops and never raise.

## Service Discovery

```python
# List instances (healthy only by default)
instances = nacos.list_instances("user-service")

# List all instances of a specific group
instances = nacos.list_instances("user-service", group="DEFAULT_GROUP", healthy_only=False)

# Get a single healthy instance
instance = nacos.get_one_healthy_instance("user-service")
```

- `service_name` is required; an empty value follows the `NACOS_FAIL_FAST` rule.
- `group` falls back to `NACOS_GROUP_NAME` when omitted.
- `healthy_only=True` (default) returns only healthy instances; `healthy_only=False`
  returns all instances.
- An empty result is returned as an empty list (not an error).
- `get_one_healthy_instance()` supports pluggable selection strategies
  (`first`, `random`, `weight`) and optional cluster/metadata filtering. See
  "Service Discovery Enhancements (0.4.0)" below.

## Configuration Center

```python
content = nacos.get_config("application.yaml")
```

`data_id` is required. `group` falls back to `NACOS_CONFIG_GROUP` (and then to
`NACOS_GROUP_NAME`) when omitted. The raw content string from Nacos is returned
as-is; no YAML, JSON, or dict parsing is performed.

## Production Readiness (0.3.0)

Version 0.3.0 adds features aimed at production use: retries, a request-timeout
setting, an optional health-check route, a runtime status inspector, and finer
control over auto-registration.

### Retry

`register_instance()`, `deregister_instance()`, `list_instances()`, and
`get_config()` are wrapped in a unified retry helper.

- `NACOS_RETRY_ENABLED` (default `True`): enable retries. When `False`, each
  operation runs exactly once.
- `NACOS_RETRY_TIMES` (default `3`): maximum number of attempts (not extra
  retries). `3` means the operation is attempted up to 3 times.
- `NACOS_RETRY_INTERVAL` (default `1.0`): seconds to wait between attempts.

Retry attempts must be an integer greater than or equal to `1`; the interval
must be a finite number greater than or equal to `0`. Numeric strings are
accepted. These values are ignored when retries are disabled.

Each failed attempt is logged at `warning` level. After the final failure the
`NACOS_FAIL_FAST` rule decides whether to raise or return a safe default.
Deterministic input and validation errors fail immediately without retrying or
waiting for backoff.

### Request Timeout

- `NACOS_REQUEST_TIMEOUT` (default `5.0`) is passed to synchronous SDK 2.x
  configuration-center `get_config(..., timeout=...)` calls.
- The timeout must be a finite number greater than `0` and is ignored when the
  configuration center is disabled.

### Health Check Route

When `NACOS_HEALTH_CHECK_ENABLED` is `True`, a Flask route is registered at
`NACOS_HEALTH_CHECK_PATH` (default `/health/nacos`). It reports only the
extension's internal state and never calls the Nacos server, so it stays fast.

```json
{
  "status": "ok",
  "nacos_enabled": true,
  "client_initialized": true,
  "registered": true,
  "service_name": "fund-service",
  "service_ip": "127.0.0.1",
  "service_port": 5000
}
```

When Nacos is disabled:

```json
{
  "status": "disabled",
  "nacos_enabled": false,
  "client_initialized": false,
  "registered": false
}
```

When client initialization failed:

```json
{
  "status": "error",
  "nacos_enabled": true,
  "client_initialized": false,
  "registered": false
}
```

The route is registered idempotently: repeated `init_app(app)` calls or a
pre-existing route will not cause Flask to raise.

### Runtime Status

```python
status = nacos.get_status()
```

Returns the extension's internal state and non-sensitive configuration only. It
never calls Nacos and never includes `NACOS_PASSWORD`, `NACOS_ACCESS_KEY`, or
`NACOS_SECRET_KEY`:

```python
{
    "nacos_enabled": True,
    "client_initialized": True,
    "registered": True,
    "service_name": "fund-service",
    "service_ip": "127.0.0.1",
    "service_port": 5000,
    "server_addr": "127.0.0.1:8848",
    "namespace_id": "",
}
```

### Auto-registration Control

Two switches control init-time registration:

- `NACOS_AUTO_REGISTER` (default `True`): master switch for auto-registration.
- `NACOS_AUTO_REGISTER_ON_INIT` (default `True`): whether `init_app(app)`
  performs the auto-registration.

The service is auto-registered during `init_app(app)` only when both are `True`
(and `NACOS_REGISTER_ENABLED` is `True`). You can always register manually:

```python
nacos.register_instance()
```

When init-time registration is active, its deterministic settings are checked
before the SDK client is created. With `NACOS_FAIL_FAST=True`, invalid settings
raise `NacosValidationError` directly from `FlaskNacos(app)` or `init_app(app)`
and no partial `app.extensions["nacos"]` state is retained. With fail-fast
disabled, the error is logged, automatic registration is skipped, and config
center and discovery operations remain available. If any auto-registration
switch is off, a service name is not required until `register_instance()` is
called manually.

### Gunicorn / Multi-worker Deployment

Under Gunicorn/uWSGI each worker process runs `init_app` and keeps independent
local registration state. However, Nacos identifies an instance by its service,
group, cluster, IP, and port: workers that advertise the same IP and port refer
to one shared Nacos instance, not one instance per worker. For a shared endpoint,
disable worker exit deregistration with `NACOS_DEREGISTER_ON_EXIT=False`, or use
one external coordinator to own registration and deregistration.

In production, always set `NACOS_SERVICE_NAME`, `NACOS_SERVICE_IP`, and
`NACOS_SERVICE_PORT` explicitly rather than relying on auto-detection.

The startup guarantee begins when `FlaskNacos(app)` or `init_app(app)` actually
runs. A WSGI server configured for lazy application loading may not construct
the Flask app until its first request. Use eager loading (for example Gunicorn
`--preload`, where appropriate) and invoke the application factory during
process startup when configuration errors must prevent the server from
accepting requests.

## Production Deployment & Service Discovery (0.4.0)

Version 0.4.0 focuses on multi-worker deployment safety and richer service
discovery: per-process registration lifecycle, safe deregistration, instance
normalization, discovery filtering, and pluggable selection strategies.

### Multi-worker Registration (Gunicorn / uWSGI)

Under Gunicorn or uWSGI, the master process forks multiple workers and each
worker runs `init_app`. flask-nacos tracks registration state per process, but
workers advertising the same service/group/cluster/IP/port update the same
Nacos instance identity:

- `NACOS_REGISTER_ONCE_PER_PROCESS` (default `True`): within the same process,
  once `register_instance()` succeeds, repeated calls are skipped. When a worker
  is forked and the process id changes, the new worker is allowed to register
  its own instance.
- On shutdown, `deregister_instance()` only deregisters the instance registered
  by the current process. If the recorded registration pid differs from the
  current process (for example the master vs a worker), deregistration is logged
  and skipped so another process's instance is not removed by mistake.

Gunicorn example (each worker initializes the extension):

```python
# wsgi.py
from myapp import create_app

app = create_app()  # init_app runs here in each forked worker
```

```bash
gunicorn -w 4 wsgi:app
```

uWSGI behaves the same way. When workers share one advertised endpoint, do not
let an individual worker remove it while other workers still serve traffic.
Set `NACOS_DEREGISTER_ON_EXIT = False`, or disable per-worker automatic
registration and let one external coordinator own the shared lifecycle.

### Deregistration on Exit

- `NACOS_DEREGISTER_ON_EXIT` (default `True`): whether an `atexit` handler is
  registered to deregister on process exit.
- The `atexit` handler is only registered when both `NACOS_AUTO_DEREGISTER` and
  `NACOS_DEREGISTER_ON_EXIT` are `True`, and it is registered at most once per
  extension instance (repeated `init_app(app)` calls do not add duplicates).
- The handler only deregisters an instance that this extension successfully
  registered; it is a no-op when registration never occurred or failed.

### Instance Normalization

- `NACOS_INSTANCE_NORMALIZE` (default `True`): when enabled, `list_instances()`
  returns a list of standard dicts. When disabled, the raw SDK instances are
  returned unchanged.

```python
instance = nacos.normalize_instance(raw_sdk_instance)
```

The standard dict shape:

```python
{
    "ip": "127.0.0.1",
    "port": 5000,
    "service_name": "user-service",
    "cluster_name": "DEFAULT",
    "weight": 1.0,
    "healthy": True,
    "enabled": True,
    "ephemeral": True,
    "metadata": {},
}
```

`normalize_instance()` accepts dict or attribute-style instances and parses
string boolean fields correctly. A usable instance requires a non-empty string
IP and an integer port in `1-65535`; malformed endpoints return `None`, and are
skipped during discovery without failing the whole call. Invalid or non-finite
weights fall back to `1.0`.

### Discovery Filtering

`list_instances()` accepts optional `cluster` and `metadata` filters:

```python
nacos.list_instances("user-service", cluster="CANARY")
nacos.list_instances("user-service", metadata={"version": "v1"})
```

- `cluster` falls back to `NACOS_DISCOVERY_CLUSTER` when not provided.
- `metadata` falls back to `NACOS_DISCOVERY_METADATA` when omitted or `None`;
  pass `{}` to explicitly disable the configured metadata filter.
- When `cluster` is set, only instances in that cluster are returned.
- When `metadata` is set, only instances whose metadata contains all the given
  key/value pairs are returned.
- An empty result after filtering is returned as an empty list.

### Selection Strategies

`get_one_healthy_instance()` accepts an optional `strategy` (falling back to
`NACOS_DISCOVERY_STRATEGY`, default `first`), plus the same `cluster`/`metadata`
filters:

```python
# first (default): return the first healthy instance
nacos.get_one_healthy_instance("user-service", strategy="first")

# random: pick a random healthy instance
nacos.get_one_healthy_instance("user-service", strategy="random")

# weight: weighted-random selection using each instance's weight
nacos.get_one_healthy_instance("user-service", strategy="weight")
```

Currently supported strategies: `first`, `random`, `weight`.

- `first`: returns the first healthy instance.
- `random`: returns a uniformly random healthy instance.
- `weight`: weighted-random selection using each instance's `weight` (missing
  weight defaults to `1.0`; instances with weight `<= 0` are ignored; if all
  weights are `<= 0` the strategy degrades to `first`).
- When there are no healthy instances, `None` is returned.
- An unsupported strategy follows the `NACOS_FAIL_FAST` rule (`None` when
  `False`, raises when `True`).

### Runtime Status (new fields)

`get_status()` now also reports process and discovery information (still
secret-free and without calling Nacos):

```python
{
    # ... existing fields ...
    "current_pid": 12345,
    "registered_pid": 12345,
    "register_once_per_process": True,
    "deregister_on_exit": True,
    "discovery_strategy": "first",
    "instance_normalize": True,
    "health_check_enabled": True,
    "health_check_path": "/health/nacos",
}
```

### Configuration Center (unchanged)

`get_config()` still returns the raw config content from Nacos as-is; no YAML,
JSON, or dict parsing is performed.

## Configuration Reference

Username and password must be configured together; access key and secret key
must be configured together. Do not configure both authentication methods at
the same time.

| Key | Default | Description |
| --- | --- | --- |
| `NACOS_ENABLED` | `True` | Master switch; when `False` no client is created. |
| `NACOS_SERVER_ADDR` | `"127.0.0.1:8848"` | Nacos server address (required). |
| `NACOS_NAMESPACE_ID` | `""` | Namespace id. |
| `NACOS_USERNAME` | `None` | Username for authentication. |
| `NACOS_PASSWORD` | `None` | Password for authentication. |
| `NACOS_ACCESS_KEY` | `None` | Access key for authentication. |
| `NACOS_SECRET_KEY` | `None` | Secret key for authentication. |
| `NACOS_GROUP_NAME` | `"DEFAULT_GROUP"` | Default group. |
| `NACOS_REGISTER_ENABLED` | `True` | Enable init-time automatic registration; manual registration remains available. |
| `NACOS_AUTO_REGISTER` | `True` | Auto register during `init_app`. |
| `NACOS_AUTO_DEREGISTER` | `True` | Auto deregister on exit. |
| `NACOS_SERVICE_NAME` | `None` | Service name (required to register). |
| `NACOS_SERVICE_IP` | `None` | Service IP; auto-detected if unset. |
| `NACOS_SERVICE_PORT` | `None` | Service port (required to register). |
| `NACOS_SERVICE_GROUP` | `"DEFAULT_GROUP"` | Group used for registration. |
| `NACOS_SERVICE_CLUSTER` | `"DEFAULT"` | Cluster name. |
| `NACOS_SERVICE_WEIGHT` | `1.0` | Load-balancing weight. |
| `NACOS_SERVICE_METADATA` | `{}` | Instance metadata dict. |
| `NACOS_SERVICE_EPHEMERAL` | `True` | Register as ephemeral instance. |
| `NACOS_SERVICE_HEARTBEAT_INTERVAL` | `5.0` | SDK heartbeat interval in seconds for ephemeral instances. |
| `NACOS_SERVICE_HEALTHY` | `True` | Initial healthy flag. |
| `NACOS_SERVICE_ENABLED` | `True` | Instance enabled flag. |
| `NACOS_CONFIG_ENABLED` | `True` | Enable config-center features. |
| `NACOS_CONFIG_DATA_ID` | `None` | Default config data id. |
| `NACOS_CONFIG_GROUP` | `"DEFAULT_GROUP"` | Default config group. |
| `NACOS_RETRY_ENABLED` | `True` | Enable retries for Nacos operations. |
| `NACOS_RETRY_TIMES` | `3` | Maximum number of attempts per operation. |
| `NACOS_RETRY_INTERVAL` | `1.0` | Seconds between retry attempts. |
| `NACOS_REQUEST_TIMEOUT` | `5.0` | Timeout passed to config-center read calls. |
| `NACOS_HEALTH_CHECK_ENABLED` | `False` | Register the Flask health-check route. |
| `NACOS_HEALTH_CHECK_PATH` | `"/health/nacos"` | Path of the health-check route. |
| `NACOS_STATUS_ENABLED` | `True` | Deprecated no-op retained for 1.x compatibility; planned for removal in 2.0. |
| `NACOS_AUTO_REGISTER_ON_INIT` | `True` | Auto register during `init_app` (with `NACOS_AUTO_REGISTER`). |
| `NACOS_REGISTER_ONCE_PER_PROCESS` | `True` | Register only once per process; a forked worker (new pid) may re-register. |
| `NACOS_DEREGISTER_ON_EXIT` | `True` | Register an `atexit` handler to deregister on process exit. |
| `NACOS_DISCOVERY_STRATEGY` | `"first"` | Default strategy for `get_one_healthy_instance` (`first`/`random`/`weight`). |
| `NACOS_DISCOVERY_CLUSTER` | `None` | Default cluster filter for discovery. |
| `NACOS_DISCOVERY_METADATA` | `{}` | Default metadata filter for discovery. |
| `NACOS_INSTANCE_NORMALIZE` | `True` | Return normalized instance dicts from `list_instances`. |
| `NACOS_FAIL_FAST` | `False` | Raise on Nacos errors when `True`. |
| `NACOS_LOG_ENABLED` | `False` | Master switch for Flask-Nacos safety logs; SDK-native logs remain silent. |
| `NACOS_LOG_LEVEL` | `"INFO"` | Flask-Nacos log level (`DEBUG`/`INFO`/`WARNING`/`ERROR`/`CRITICAL`). |
| `NACOS_LOG_CONSOLE_ENABLED` | `True` | Print normal and error records to the console when logging is enabled. |
| `NACOS_LOG_FILE_ENABLED` | `True` | Write a rotating log file when logging is enabled. |
| `NACOS_LOG_PATH` | `"./logs"` | Directory for the Flask-Nacos log file. |
| `NACOS_LOG_FILENAME` | `"flask-nacos.log"` | Log filename; paths and directory traversal are rejected. |
| `NACOS_LOG_FORMAT` | `"%(asctime)s [%(levelname)s] %(name)s: %(message)s"` | Log format string. |
| `NACOS_LOG_PROPAGATE` | `True` | Propagate to parent loggers; the root logger is never modified. |
| `NACOS_LOG_MAX_BYTES` | `10485760` | Positive int sets the rotating file size; `None` uses a plain `FileHandler`. |
| `NACOS_LOG_BACKUP_COUNT` | `5` | Backup count for the rotating file handler. |

### Logging

`NACOS_LOG_*` controls only the sanitized records produced by Flask-Nacos. The
underlying SDK-native loggers are always silent because they may include tokens,
request parameters, or configuration content. By default no log file or
`~/logs/nacos` directory is created and the root logger is not modified. When
`NACOS_LOG_ENABLED=True`, console and rotating-file output are enabled by
default. `NACOS_LOG_PATH` is created for `NACOS_LOG_FILENAME`; the defaults
produce `./logs/flask-nacos.log`. When
logging is disabled, the configured directory is never created.
Console records are colored by level (`DEBUG` blue, `INFO` green, `WARNING`
yellow, `ERROR` red, `CRITICAL` bold red); file records never contain ANSI
color codes.

```python
app.config.update(
    NACOS_LOG_ENABLED=True,
    NACOS_LOG_LEVEL="INFO",
    NACOS_LOG_CONSOLE_ENABLED=True,
    NACOS_LOG_FILE_ENABLED=True,
    NACOS_LOG_PATH="/var/log/flask-nacos",
    NACOS_LOG_FILENAME="service.log",
    NACOS_LOG_PROPAGATE=True,
)
```

To disable Flask-Nacos safety logs as well:

```python
app.config.update(
    NACOS_LOG_ENABLED=False,
)
```

See [Configuration](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/configuration.md)
for the full logging reference.

## Exception Handling

The behavior on failure is controlled by `NACOS_FAIL_FAST`. This covers Nacos
client initialization, registration, deregistration, discovery, registration
parameter validation, and local IP auto-detection:

- `NACOS_FAIL_FAST = False` (default): failures are logged and do not prevent
  the Flask app from starting. Methods return safe defaults:
  - `register_instance()` -> `False`
  - `deregister_instance()` -> `False`
  - `list_instances()` -> `[]`
  - `get_one_healthy_instance()` -> `None`
  - `get_config()` -> `None`
- `NACOS_FAIL_FAST = True`: failures raise an exception. Active automatic
  registration settings are preflighted synchronously in `init_app(app)` before
  client creation or extension-state installation.

Exception hierarchy:

```python
from flask_nacos import (
    FlaskNacosError,
    NacosConfigError,
    NacosClientError,
    NacosValidationError,
    NacosRegistrationError,
    NacosDeregistrationError,
    NacosDiscoveryError,
    NacosLoggingError,
)
```

- `FlaskNacosError` — base class.
- `NacosConfigError` — invalid config or config-read failures.
- `NacosClientError` — Nacos client creation/usage failures.
- `NacosValidationError` — deterministic input or numeric configuration validation failures (subclass
  of `NacosConfigError`).
- `NacosRegistrationError` — service registration failures.
- `NacosDeregistrationError` — service deregistration failures.
- `NacosDiscoveryError` — discovery failures.
- `NacosLoggingError` — logging configuration failures (only when `NACOS_FAIL_FAST=True`).

## Production Notes

- Under multi-worker servers, workers that advertise the same service identity
  and IP:port share one Nacos instance. Disable worker exit deregistration or
  use a single external lifecycle coordinator for that shared endpoint.
- Synchronous `nacos-sdk-python` 2.x does not provide reliable HTTPS certificate
  verification controls. Use it only on a trusted network or behind a TLS proxy
  or sidecar that validates the Nacos server certificate.
- Never commit real credentials, internal Nacos addresses, or internal IPs.
  Prefer environment variables for `NACOS_USERNAME` / `NACOS_PASSWORD`.
- Secrets (`NACOS_PASSWORD`, `NACOS_ACCESS_KEY`, `NACOS_SECRET_KEY`) are never
  written to logs.
- A sensitive-information scan (`scripts/check_sensitive_info.py`) runs in CI to
  guard against accidentally committed secrets, private IPs, or `.env` files.

## Examples

Runnable examples live in the [`examples/`](https://github.com/pumpkin-nbc/Flask-Nacos/tree/master/examples) directory:

- [`examples/basic_app.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/basic_app.py) — Flask standard mode with
  `FlaskNacos(app)`.
- [`examples/beginner_app.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/beginner_app.py) — progressive first-run
  example that starts without Nacos; follow the [quickstart](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/quickstart.md).
- [`examples/factory_app.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/factory_app.py) — Flask application
  factory mode with `nacos.init_app(app)`.
- [`examples/complete_factory_app.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/complete_factory_app.py) —
  environment-driven, end-to-end factory integration; follow the
  [complete guide](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/complete-example.md).
- [`examples/service_registration.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/service_registration.py) —
  registration in a trusted startup/shutdown lifecycle, without unauthenticated
  HTTP management endpoints.
- [`examples/service_discovery.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/service_discovery.py) — listing
  instances, cluster/metadata filtering, and `get_one_healthy_instance()`.
- [`examples/health_check_app.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/health_check_app.py) — enabling the
  health-check route via `NACOS_HEALTH_CHECK_ENABLED` / `NACOS_HEALTH_CHECK_PATH`.
- [`examples/production_config.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/production_config.py) — env-var
  driven configuration for multi-worker deployments.
- [`examples/docker-compose-nacos.yml`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/examples/docker-compose-nacos.yml) — a
  local Nacos for manual testing (local use only).

The bundled local Compose setup uses `127.0.0.1:8848` with authentication
disabled. Replace it with an authenticated deployment and inject credentials
through environment variables or a secret manager in production.

Start a local Nacos for manual testing:

```bash
docker compose -f examples/docker-compose-nacos.yml up -d
```

## Local Development & Testing

Install the dev extras into your virtual environment, then run the tooling. All
Nacos interactions in the test suite are mocked, so no real Nacos server is
required.

```bash
# Linux / macOS
.venv/bin/python -m pytest
.venv/bin/python -m ruff check .
.venv/bin/python -m mypy flask_nacos
.venv/bin/python -m build
.venv/bin/python -m twine check dist/*
```

```powershell
# Windows (PowerShell)
.venv\Scripts\python -m pytest
.venv\Scripts\python -m ruff check .
.venv\Scripts\python -m mypy flask_nacos
.venv\Scripts\python -m build
.venv\Scripts\python -m twine check dist/*
```

Test coverage is reported automatically (`--cov=flask_nacos`); there is no hard
coverage threshold, so it never blocks development.

## Type Hints

`flask-nacos` ships inline type hints and a `py.typed` marker (PEP 561), so type
checkers such as mypy and Pyright pick up the package's types automatically once
it is installed — no separate stub package is needed.

## PyPI Release Preparation

Before publishing a release, run the one-shot pre-release checks from the
repository root:

```bash
bash scripts/release_check.sh
```

This runs `ruff`, `mypy`, `pytest`, the version-consistency check, the
sensitive-information scan, a clean `python -m build`, `twine check`, and the
package-content check — without uploading anything. The individual scripts are:

- [`scripts/check_version.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/scripts/check_version.py) — verifies the version
  is consistent across `pyproject.toml`, `__version__`, and `CHANGELOG.md`.
- [`scripts/check_sensitive_info.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/scripts/check_sensitive_info.py) — scans
  for hardcoded secrets, private IPs, internal domains, and `.env` files.
- [`scripts/check_package.py`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/scripts/check_package.py) — validates wheel/sdist
  contents, metadata, licensing, PyPI-safe links, and artifact freshness.

The manual `Release` workflow ([`.github/workflows/release.yml`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/.github/workflows/release.yml))
reruns these checks and publishes to TestPyPI through OIDC. A protected
`vX.Y.Z` tag triggers the separately approved PyPI job. See
[`docs/release.md`](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/docs/release.md) for the full release procedure, TestPyPI/PyPI
flow, Trusted Publisher setup, and required GitHub Environments.

Ordinary branch pushes never publish packages. Only a protected version tag
that passes every release check can reach the manually approved `pypi`
environment.

## Compatibility

- Flask: `>=1.0, <4.0`
- Python: `>=3.8`
- Nacos: 2.x
- Nacos SDK: `nacos-sdk-python>=2.0.0,<3.0.0` (synchronous client)

## License

Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/LICENSE) and
[NOTICE](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/NOTICE).
Report suspected vulnerabilities privately as described in the
[Security Policy](https://github.com/pumpkin-nbc/Flask-Nacos/blob/master/SECURITY.md).
