nolar / kopf

A Python framework to write Kubernetes operators in just a few lines of code

Home Page:https://kopf.readthedocs.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Good practices - updating state upon retrying

lkoniecz opened this issue · comments

Keywords

retries, patching, state

Problem

https://kopf.readthedocs.io/en/stable/errors/#

kopf retries upon exception, if the exception is raised then the handler fails fast without returning, hence I can't update custom resource status

real-life example
my custom resource represence a HTTP request
I want to retry upon 5xx and timeouts using kopf build-int handlers retry logic

@kopf.on.update('httprequests', retries=3, backoff=10)
def handler(memo: kopf.Memo, spec, name, namespace, logger, **kwargs):
   r = requests.request(some_url)
   if r.status_code == 500:
       what now?

I can manually patch the resource and luckily it does not trigger on_update handler, but it does not seem like the right thing to do. For instance its not automatically logged via handler built-in logger.

I'm probably missing something, but why not just do this?

@kopf.on.update('httprequests', retries=3, backoff=10)
def handler(memo: kopf.Memo, spec, name, namespace, logger, **kwargs):
    r = requests.request(some_url)
    if r.status_code == 500:
        raise kopf.TemporaryError(f"Resource at {some_url} returns {r.status_code}", delay=60)

That does not update status field.

There is the patch kwarg. You can populate it with whatever you want during the handler execution. Kopf will add a few things of its own later after the error (or success) — and will apply it to the k8s api.

Manually patching the resource is also a right way to go, there is nothing wrong with it (except for one extremely rare edge case under high load, which will be fixed soon). The only downside is that you will have 2 patch api calls: one from you, one from kopf; and you will also have to authenticate somehow not with kopf’s login machinery.

@nolar
if I read the docs correctly https://kopf.readthedocs.io/en/stable/kwargs/#patching patch is a pass through object that I can fill with anything that will get passed to the patching logic

@kopf.on.update('httprequests', retries=3, backoff=10)
def handler(memo: kopf.Memo, spec, name, namespace, logger, **kwargs):
    r = requests.request(some_url)
    if r.status_code == 500:
       kwargs['patch'] = {
            'status': {
                'handler': {
                    'httpStatusCode': 500
                }
            }
        }
        raise kopf.TemporaryError(f"Resource at {some_url} returns {r.status_code}", delay=60)

is it the right way to do? I am asking, because following snippet does not work.

The right way. But in your case, you override the kwarg key in the local dict, you do not modify the object itself. Try this:

def …(…, patch, **kwargs):
    patch.status.setdefault('handler', {})['httpStatusCode'] = 500

Perfect, it works.

Thanks for the guidance.

Closing/