def METHOD_NAME(
    fn=None,
    maxsize=128,
    typed=False,
    *,
    cache_exceptions=True,
):
    def wrapper(fn):
        _origin = unpartial(fn)
        if not asyncio.iscoroutinefunction(_origin):
            raise RuntimeError("Coroutine function is required, got {}".format(fn))
        # functools.partialmethod support
        if hasattr(fn, "_make_unbound_method"):
            fn = fn._make_unbound_method()
        @wraps(fn)
        async def wrapped(*fn_args, **fn_kwargs):
            if wrapped.closed:
                raise RuntimeError("alru_cache is closed for {}".format(wrapped))
            loop = asyncio.get_event_loop()
            key = _make_key(fn_args, fn_kwargs, typed)
            fut = wrapped._cache.get(key)
            if fut is not None:
                if not fut.done():
                    _cache_hit(wrapped, key)
                    return await asyncio.shield(fut)
                exc = fut._exception
                if exc is None or cache_exceptions:
                    _cache_hit(wrapped, key)
                    return fut.result()
                # exception here and cache_exceptions == False
                wrapped._cache.pop(key)
            fut = loop.create_future()
            task = loop.create_task(fn(*fn_args, **fn_kwargs))
            task.add_done_callback(partial(_done_callback, fut))
            wrapped.tasks.add(task)
            task.add_done_callback(wrapped.tasks.remove)
            wrapped._cache[key] = fut
            if maxsize is not None and len(wrapped._cache) > maxsize:
                wrapped._cache.popitem(last=False)
            _cache_miss(wrapped, key)
            return await asyncio.shield(fut)
        _cache_clear(wrapped)
        wrapped._origin = _origin
        wrapped.closed = False
        wrapped.cache_info = partial(_cache_info, wrapped, maxsize)
        wrapped.cache_clear = partial(_cache_clear, wrapped)
        wrapped.invalidate = partial(_cache_invalidate, wrapped, typed)
        wrapped.close = partial(_close, wrapped)
        wrapped.open = partial(_open, wrapped)
        if _is_ci:
            _all_wrapped.add(wrapped)
        return wrapped
    if fn is None:
        return wrapper
    if callable(fn) or hasattr(fn, "_make_unbound_method"):
        return wrapper(fn)
    raise NotImplementedError("{} decorating is not supported".format(fn))