Home / OCI

OCIHow-toIntermediate

Transformation: move scheduled scripts and small APIs to OCI Functions, API Gateway and Resource Scheduler

Retire the always-on VM that runs cron jobs and tiny internal APIs. Package scripts as OCI Functions, trigger them on a schedule or from events, expose HTTP endpoints through API Gateway and use resource principals instead of keys.

Deepak Bhardwaj3 min read

Applies toOCI Functions (Fn Project), OCI API Gateway, OCI Events, Resource Scheduler, OCIR, Fn CLI

Pick the trigger

Today Serverless target
Cron job calling OCI APIs Function invoked on a schedule
Script triggered by a file landing Function triggered by an Object Storage event (Events service)
Small internal REST API Function behind API Gateway
Start/stop instances on a timetable Resource Scheduler (no code)
Long-running jobs (hours) Container Instances or OKE jobs instead — Functions have a maximum timeout

1. Create an application

oci fn application create --compartment-id $C --display-name ops-functions \
  --subnet-ids '["<private-subnet-ocid>"]'
fn create context oci-fra --provider oracle
fn use context oci-fra
fn update context oracle.compartment-id $C
fn update context registry fra.ocir.io/<ns>/ops

2. Write the function

fn init --runtime python purge-old-exports
# func.py
import io, json, datetime, oci
from fdk import response

def handler(ctx, data: io.BytesIO = None):
    signer = oci.auth.signers.get_resource_principals_signer()
    os_client = oci.object_storage.ObjectStorageClient(config={}, signer=signer)
    ns = os_client.get_namespace().data
    cutoff = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=30)
    deleted = 0
    objs = oci.pagination.list_call_get_all_results(os_client.list_objects, ns, "exports", fields="timeCreated").data.objects
    for o in objs:
        if o.time_created < cutoff:
            os_client.delete_object(ns, "exports", o.name)
            deleted += 1
    return response.Response(ctx, response_data=json.dumps({"deleted": deleted}), headers={"Content-Type": "application/json"})
fn deploy --app ops-functions
fn invoke ops-functions purge-old-exports

3. Resource principal permissions

ALL {resource.type = 'fnfunc', resource.compartment.id = '<comp-ocid>'}     -- dynamic group 'fn-ops'
Allow dynamic-group 'Default'/'fn-ops' to manage objects in compartment data where target.bucket.name = 'exports'

No API keys inside the function.

4. Schedule it

Create a schedule that invokes the function (OCI Resource Scheduler supports function invocation on a cron-like schedule; check the regions and actions available to you). Alternatives: an OCI DevOps or external scheduler calling the function's invoke endpoint, or Events for event-driven jobs.

5. Expose an API

oci api-gateway gateway create --compartment-id $C --endpoint-type PRIVATE --subnet-id <subnet-ocid> --display-name gw-internal

Deployment spec route:

{ "routes": [ { "path": "/inventory", "methods": ["GET"],
   "backend": { "type": "ORACLE_FUNCTIONS_BACKEND", "functionId": "<function-ocid>" } } ],
  "requestPolicies": { "authentication": { "type": "JWT_AUTHENTICATION", "tokenHeader": "Authorization" } } }

Add authentication (JWT from your IdP or a custom authorizer function) and rate limiting.

6. Observe

Enable function invoke logs in OCI Logging, and alarm on the FunctionExecutionErrors-type metrics in the oci_faas namespace. Check metric names in your region's Monitoring metric explorer.

Note

Cold starts add latency to the first call after idle time. Use provisioned concurrency for latency-sensitive APIs.

Checklist

  • Jobs inventoried; long-running ones routed elsewhere
  • Functions use resource principals with narrow policies
  • Schedules/events wired; API Gateway with auth
  • Logs and alarms on errors
  • Old VM retired