# Trabajos y trabajos por lotes
El trabajo largo corre en segundo plano como un trabajo, que usted sigue por su ID.
| Usted quiere | Use |
| --- | --- |
| Cambiar filas con unas pocas sentencias SQL, publicadas a la vez | `nexus.start_batch_job()` |
| Ejecutar su propio script de Spark en Python | `nexus.jobs.submit()` |
## Antes de empezar [#antes-de-empezar]
- El **Acceso** de su clave permite escribir.
- El espacio de trabajo tiene créditos; si no, un trabajo se rechaza antes de empezar.
- Todos los ejemplos suponen `nexus = Nexus.connect()`.
Un trabajo gasta los créditos del espacio de trabajo mientras corre. Revise su saldo en .
## Trabajos por lotes [#trabajos-por-lotes]
Un trabajo por lotes ejecuta de 1 a 50 sentencias SQL que cambian filas y las publica como un solo cambio: llegan todas, o ninguna.
### Inicie un trabajo por lotes [#inicie-un-trabajo-por-lotes]
```python title="close_old_orders.py"
import time
from klarety import Nexus, RefusedError, WaitingForOwnerError
with Nexus.connect() as nexus:
try:
job = nexus.start_batch_job([
"UPDATE orders SET status = 'closed' WHERE ordered_at < DATE '2026-01-01'",
"DELETE FROM orders WHERE status = 'test'",
])
except RefusedError as refused:
raise SystemExit(f"Refused: {refused}")
try:
state = nexus.jobs.describe(job["job_id"])
while state["state"] in ("running", "publishing"):
time.sleep(5)
state = nexus.jobs.describe(job["job_id"])
print("Ended as", state["state"])
except WaitingForOwnerError as waiting:
print("Waiting for the owner's OK:", waiting, waiting.job_id)
```
### Sígalo [#sígalo]
`jobs.describe()` informa `running`, luego `publishing` y luego cómo terminó el trabajo: `succeeded`, `failed`, `declined` o `expired`.
Algunos cambios necesitan el visto bueno del dueño de los datos. Entonces `jobs.describe()` lanza `WaitingForOwnerError` con el `job_id` para seguirlo. El trabajo queda en espera, no falló: nunca lo reenvíe.
### Reglas [#reglas]
- Cada sentencia debe leer o cambiar filas. Cambie columnas con [Tablas y esquemas](/docs/es/developers/tables).
- Una tabla vacía no tiene desde dónde partir. Agregue sus primeras filas con `tables.edit_rows()` o con una carga.
## Trabajos con script de Spark [#trabajos-con-script-de-spark]
`jobs.submit()` ejecuta un script de Spark en Python dentro de los recursos que permite su plan.
### Envíe un script [#envíe-un-script]
```python
from klarety import Nexus, RefusedError
with Nexus.connect() as nexus:
try:
job = nexus.jobs.submit(script_uri, args=["--day", "2026-11-09"])
except RefusedError as refused:
raise SystemExit(f"Job refused: {refused}")
print(job["job_id"], job["state"])
```
- `script_uri` es un archivo `.py` en el almacenamiento propio de su espacio de trabajo; cualquier otro lugar se rechaza.
- `args` se pasan al script, hasta 64.
- Un trabajo corre como máximo lo que su plan permite correr a una sentencia.
### Sígalo o cancélelo [#sígalo-o-cancélelo]
```python
print(nexus.jobs.describe(job["job_id"])) # submitted, running, succeeded, failed or cancelled
nexus.jobs.cancel(job["job_id"])
```
Cuando un trabajo falla, `exit_reason` dice por qué.
## Qué puede salir mal [#qué-puede-salir-mal]
| Excepción | Causa | Qué hacer |
| --- | --- | --- |
| `RefusedError` | Una sentencia no cambia filas, el script no es un `.py` de su almacenamiento, o pidió más de lo que permite su plan. | Lea el mensaje y corrija la solicitud. |
| `InsufficientCreditsError` | El espacio de trabajo no puede pagar el trabajo. | Agregue créditos. |
| `WaitingForOwnerError` | El cambio espera el visto bueno del propietario. | Siga `job_id`; no lo reenvíe. |
| `NotFoundError` | No existe ese trabajo. | Revise el ID. |
## Próximos pasos [#próximos-pasos]
- [Ejecutar SQL](/docs/es/developers/sql) para lecturas.
- [Sesiones de Spark](/docs/es/developers/spark) para Spark interactivo.
- [Límites y límites de solicitudes](/docs/es/developers/limits) para los recursos de trabajos de su plan.