Hace unos días recibí un correo de un suscriptor. La pregunta parecía simple… pero venía con truco:

Buenos días Javier, 
Tengo dos usuarios de base de datos: 
1. OWNER 
2. DBA 

El usuario DBA crea un Job Scheduler donde el propietario del Job es OWNER. 
El Job donde el propietario es OWNER y el creador es DBA corre sin problemas. 
Resulta que el usuario dueño de la cuenta DBA se retira de la empresa y la cuenta DBA es eliminada. 

Pregunta capciosa: 
¿Qué pasa con el Job Scheduler creado por el usuario? 
1) ¿Corre normal? 
2) ¿Falla? 

¿Por qué? Saludos, 

La respuesta “automática” que muchos daríamos (yo incluido) es: Si el job “es de” OWNER y OWNER sigue existiendo, debería seguir corriendo.

Pero el Scheduler guarda más información de la que solemos mirar por costumbre… y ahí es donde aparecen los sustos.

Mirar solo la columna OWNER por deformación profesional

A mi me pasa el primero.

Siempre voy a ver OWNER para saber quién es el propietario de un objeto. Puede ser que una tabla sea propietario un usuario, y el índice pertenezca a SYSTEM (si lo ha creado un DBA, a veces suele pasar), o quién es el propietario de un dblink, un sinónimo,…

Así que OWNER es la columna de referencia. Pero en el Scheduler existe otro concepto que suele pasar desapercibido: el usuario creador del job.

En los casos en los que el creador y el propietario son el mismo, no hay gran problema. Incluso cuando los jobs están creados por SYS o SYSTEM, podemos tener la garantía que el usuario creador va a existir siempre, pero aquí nos preocupa un escenario muy concreto: cuando OWNER y JOB_CREATOR son distintos.

Eso ocurre, por ejemplo, cuando un DBA (o un usuario con privilegios tipo CREATE ANY JOB) crea jobs “en nombre de” otro esquema.

 

¿Qué dice la documentación… y qué omite?

La documentación del Scheduler te explica el modelo, los privilegios, los objetos (jobs, programs, schedules, chains), y deja claro que se pueden administrar jobs de distintas formas.

Pero normalmente lo hace desde el punto de vista “funcional”: Habla de la creación, habilitarlo/deshabilitarlo, monitorizarlo,… pero no entra en la recomendación de buenas prácticas, ni te advierte de las consecuencias colaterales del offboarding (cuando se elimina la cuenta de una persona por política de seguridad).

Y aquí, en la documentación, echo en falta una nota/advertencia que diga algo así:

  • “Si haces DROP USER del creador, aunque el owner exista, el job queda en estado BROKEN.”

AskTom y Oracle Support

Pues, al parecer, ésto no sólo le ocurrió a este suscriptor ni es es una paranoia teórica. Le ha pasado a más de uno y lo podemos ver como caso real en AskTom (Chris Saxon), donde al eliminar (DROP USER) al creador, algunos jobs pasan a estado roto. Además, en el log aparece un el motivo definido de forma explícita:

  • REASON="Job creator: <usuario> dropped"

Referencia (AskTom):
https://asktom.oracle.com/ords/f?p=100:11:0::::P11_QUESTION_ID:9537363000346826584

 También existe una nota de soporte que corrobora esta casuistica (en el sentido de “esto puede pasar y hay explicación”), aunque, en mi opinión, ésto deberíamos leerlo en la documentación y no en soporte, cuando vemos que los jobs quedan rotos sin que el OWNER haya sufrido ningún cambio.

Es decir, en muchos equipos el problema se descubre cuando el job falla.

Y hay que tener cuidado, porque recrear el usuario «creador» no resuelve el problema.

Laboratorio

Connected to:
Oracle AI Database 26ai Enterprise Edition Release 23.26.0.0.0 - for Oracle Cloud and Engineered Systems
Version 23.26.0.0.0

SQL> CREATE USER owner IDENTIFIED BY "OD98@@ownerDb76";

User created.

SQL> CREATE USER javier_dba IDENTIFIED BY "JD12!!cafeDB34";SQL> 

User created.

SQL> GRANT CREATE SESSION TO owner, javier_dba;

Grant succeeded.

SQL> GRANT CREATE ANY JOB, DBA TO javier_dba;

Grant succeeded.

SQL> GRANT SELECT_CATALOG_ROLE TO owner;

Grant succeeded.

SQL> CONNECT javier_dba/"JD12!!cafeDB34"@DBORA23ai
Connected.
SQL> BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name        => 'OWNER.TESTJ',
    job_type        => 'PLSQL_BLOCK',
    job_action      => 'BEGIN NULL; END;',
    repeat_interval => 'FREQ=MINUTELY',
    enabled         => TRUE,
    auto_drop       => FALSE
  );
END;
/
  2    3    4    5    6    7    8    9   10   11  
PL/SQL procedure successfully completed.

-- DESDE OTRA TERMINAL, COMO USUARIO SYS o DBA
Connected to:
Oracle AI Database 26ai Enterprise Edition Release 23.26.0.0.0 - for Oracle Cloud and Engineered Systems
Version 23.26.0.0.0

SQL> set lines 200
SQL> column owner format a20
SQL> column job_name format a20
SQL> column job_creator format a20
SQL> SELECT owner, job_name, job_creator, enabled, state
  2  FROM   dba_scheduler_jobs
  3  WHERE  owner = 'OWNER' AND job_name = 'TESTJ';

OWNER		     JOB_NAME		  JOB_CREATOR	       ENABL STATE
-------------------- -------------------- -------------------- ----- ---------------
OWNER		     TESTJ		  JAVIER_DBA	       TRUE  SCHEDULED


-- CUIDADO! en DBA_SCHEDULER_JOB_LOG no tenemos ninguna información sobre el creador! Ni siquiera CREDENTIAL_OWNER nos informa de ello.


SQL> SELECT owner, job_name, credential_owner, destination_owner, log_date, status, additional_info
  2  FROM   dba_scheduler_job_log
  3  WHERE  owner = 'OWNER' AND job_name = 'TESTJ'
  4  ORDER  BY log_date DESC
  5  FETCH FIRST 10 ROWS ONLY;

OWNER	   JOB_N CRE DE LOG_DATE				STATUS		     ADDITIONAL_INFO
---------- ----- --- -- ----------------------------------- -------------------- --------------------
OWNER	   TESTJ	    10-FEB-26 12.24.13.100109 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.23.12.904160 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.22.12.711332 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.21.12.504966 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.20.12.494228 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.19.12.292930 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.18.12.289176 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.17.13.093724 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.16.12.892626 PM +00:00 SUCCEEDED
OWNER	   TESTJ	    10-FEB-26 12.15.12.884613 PM +00:00 SUCCEEDED

10 rows selected.


SQL> drop user javier_dba;

User dropped.

SQL> SELECT owner, job_name, credential_owner, destination_owner, log_date, status, additional_info
  2	FROM   dba_scheduler_job_log
  3	WHERE  owner = 'OWNER' AND job_name = 'TESTJ'
  4	ORDER  BY log_date DESC
  5	FETCH FIRST 10 ROWS ONLY;

OWNER	   JOB_N CR DE LOG_DATE 			   STATUS		ADDITIONAL_INFO
---------- ----- -- -- ----------------------------------- -------------------- --------------------
OWNER	   TESTJ       10-FEB-26 12.27.12.302032 PM +00:00 REASON="Job creator: JAVIER_DBA dropped"
OWNER	   TESTJ       10-FEB-26 12.26.12.111959 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.25.12.104406 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.24.13.100109 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.23.12.904160 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.22.12.711332 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.21.12.504966 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.20.12.494228 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.19.12.292930 PM +00:00 SUCCEEDED
OWNER	   TESTJ       10-FEB-26 12.18.12.289176 PM +00:00 SUCCEEDED

10 rows selected.

SQL> SELECT owner, job_name, job_creator, enabled, state
  2	 FROM	dba_scheduler_jobs
  3	 WHERE	owner = 'OWNER' AND job_name = 'TESTJ';

OWNER	   JOB_N JOB_CREATOR	      ENABL STATE
---------- ----- -------------------- ----- ---------------
OWNER	   TESTJ JAVIER_DBA	      FALSE BROKEN

Buenas prácticas

Este problema, cuando aparece, suele venir por una mala praxis de costumbre: Que sean los DBAs los responsables de crear jobs bajo esquemas de usuario.

Aquí las prevenciones deberían ir en la línea de:

  1. Definir un usuario estable para planificaciones (llámalo PLANNER / JOB_PLANNER / o similar). Al crear una cuenta estable, gestionada como cualquier service account (rotación de password, control de acceso, auditoría), y con los mínimos privilegios necesarios para administrar Scheduler en los esquemas donde aplique (bastaría con CREATE ANY JOB).
  2. Que sean los usuarios que necesiten crear jobs, que los creen bajo su propio esquema, de forma que OWNER y JOB_CREATOR sean siempre el mismo. No está mal darles la formación necesaria para que manejen el planificador y cada usuario se encargue de sus propios jobs, siempre que sean de su ámbito de aplicación (no jobs de backup, por ejemplo).
  3. Chequear dependencias antes de borrar un usuario con altos privilegios.

Para este tercer punto, estas consultas nos pueden ir bien:

SQL> variable usuario varchar2(40)
SQL> variable usuario varchar2(10)
SQL> exec :usuario:='JAVIER_DBA';

PL/SQL procedure successfully completed.

SQL> SELECT owner, job_name, job_creator, enabled, state
  2  FROM dba_scheduler_jobs
  3  WHERE job_creator = :usuario;

OWNER	   JOB_N JOB_CREATOR	      ENABL STATE
---------- ----- -------------------- ----- ---------------
OWNER	   TESTJ JAVIER_DBA	      FALSE BROKEN

Conclusión

La documentación te da el modelo del Scheduler y sus conceptos, pero no siempre te lo traduce a “operativa de vida real” (offboarding, seguridad, rotación de personal). Y ahí es donde entran los casos como el que Chris Saxon comenta en AskTom y la nota de soporte: cuando desaparece el creator, el job se rompe, y de eso no te advierte nadie.

En este caso, más importante aun que identificar OWNER de un job, para saber si ese usuario es propietario de jobs planificados, también chequear JOB_CREATOR para saber si ha creado jobs bajo otro esquema.

Hay que tener en cuenta que recrear el usuario en este caso no basta para que el job se repare.

Es preciso volver a habilitar el job desde DBMS_SCHEDULER.ENABLE.

 

SQL> CREATE USER javier_dba IDENTIFIED BY "JD12!!cafeDB34";

User created.

SQL> GRANT CREATE SESSION TO owner, javier_dba;

Grant succeeded.

SQL> GRANT CREATE ANY JOB TO javier_dba;

Grant succeeded.

SQL> BEGIN DBMS_SCHEDULER.ENABLE('OWNER.TESTJ');
2 END;
3 /

PL/SQL procedure successfully completed.

SQL> SELECT owner, job_name, job_creator, enabled, state
2 FROM dba_scheduler_jobs
3 WHERE job_creator = :usuario;

OWNER JOB_N JOB_CREATOR ENABL STATE
---------- ----- -------------------- ----- ---------------
OWNER TESTJ JAVIER_DBA TRUE SCHEDULED

Referencias

Share This