Metadata-Version: 2.4
Name: betshare-infra-mongo
Version: 0.1.0
Summary: Shared MongoDB connection-policy helpers for BetShareMarket Python services
License: ISC
Author: BetShareMarket
Author-email: dev@betsharemarket.com
Requires-Python: >=3.10,<4.0
Classifier: License :: OSI Approved
Classifier: Programming Language :: Python :: 3
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: Programming Language :: Python :: 3.14
Description-Content-Type: text/markdown

# betshare-infra-mongo

Shared MongoDB **connection-policy** helpers for BetShareMarket Python services.
These are pure helpers — there is **no `MongoClient`, no driver wrapping, no
runtime dependency**. Every function returns a plain `str` or `dict` so the
result can be splatted directly into pymongo's `MongoClient` or motor's
`AsyncIOMotorClient`:

```python
from pymongo import MongoClient
from betshare_infra_mongo import build_mongo_uri, mongo_options, resolve_db_name

client = MongoClient(build_mongo_uri(os.getenv("MONGO_URI")), **mongo_options(max_pool_size=5))
db = client[resolve_db_name()]
```

Import name: `betshare_infra_mongo`. Distribution name: `betshare-infra-mongo`.

## Why

The connection-pool / timeout knobs were copy-pasted (and drifted) across
`consumer`, `joiner-events`, and `betfair-exchange-scraper`. Uncapped or
inconsistent pools contributed to Cosmos vCore connection exhaustion. This
package centralises:

- the **fleet socket-timeout policy** (120s default),
- a **required** `max_pool_size` (no default) so every call site declares an
  explicit pool cap that can be audited,
- the **db-name resolution** (`MONGODB_DB_NAME` -> `betsharemarket`),
- the **URI normalisation** (insert the db name when missing), kept in parity
  with the TS `buildMongoURI` helper in `services/odds-worker`.

## Install

**Production (private registry, version-pinned per service):**

```toml
# in the service's pyproject.toml
betshare-infra-mongo = "^0.1.0"
```

**Local development (PATH dependency, used by the migration):**

```toml
betshare-infra-mongo = { path = "../../packages/py-infra-mongo", develop = true }
```

Or with pip: `pip install -e packages/py-infra-mongo`.

## Public interface

```python
def build_mongo_uri(base_uri: str | None) -> str: ...
def resolve_db_name() -> str: ...
def mongo_options(*, max_pool_size: int,
                  server_selection_timeout_ms: int = 30000,
                  socket_timeout_ms: int = 120000,
                  connect_timeout_ms: int = 10000,
                  **overrides) -> dict: ...
```

### `build_mongo_uri`

Ensures the URI carries a database name. Parity with
`services/odds-worker/src/utils/buildMongoURI.ts`:

- **Falsy input** (`None` **or** empty string `""`) -> `mongodb://localhost:27017/betsharemarket`
  (the TS helper uses `if (!baseURI)`, which treats `""` the same as `undefined`).
- A URI with an existing db path (anything but a bare `/`) is returned
  unchanged, query string included.
- A URI with no db path (or a bare trailing `/`) gets `/betsharemarket`
  inserted **before** any query string.
- `mongodb+srv://` is handled identically to `mongodb://`.
- A URI not matching the expected shape gets `/betsharemarket` appended
  (same fallback as the TS helper).

### `resolve_db_name`

`os.environ.get("MONGODB_DB_NAME") or "betsharemarket"`.

### `mongo_options`

Returns a **camelCase** kwargs dict (`maxPoolSize`, `serverSelectionTimeoutMS`,
`socketTimeoutMS`, `connectTimeoutMS`) — the exact keys both pymongo and motor
accept. `max_pool_size` is **required** (omitting it raises `TypeError`). Extra
`**overrides` (camelCase, e.g. `minPoolSize=1`, `maxIdleTimeMS=600000`) pass
through verbatim and win over the named defaults.

