@Override
        protected void run(ChannelHandlerContext ctx) {
            try {
                isMaxConnectionAgeExceeded = true;

                // A connection exceeding the max age will be closed with:
                // - HTTP/2 server: Sending GOAWAY frame after writing headers
                // - HTTP/1 server: Sending 'Connection: close' header when writing headers
                // - HTTP/2 client
                //   - Sending GOAWAY frame after receiving the end of a stream
                //   - Or closed by this task if the connection is idle
                // - HTTP/1 client
                //   - Close the connection after fully receiving a response
                //   - Or closed by this task if the connection is idle

                if (!isServer && !hasRequestsInProgress(ctx)) {
                    logger.debug("{} Closing a {} connection exceeding the max age: {}ns",
                                 ctx.channel(), name, maxConnectionAgeNanos);
                    ctx.channel().close();
                }
            } catch (Exception e) {
                logger.warn("Unexpected error occurred while closing a connection exceeding the max age", e);
            }
        }
State changes from IDLE -> PING_SCHEDULED -> PENDING_PING_ACK -> IDLE and so on. When the
channel is inactive then the state changes to SHUTDOWN.
core/src/main/java/com/linecorp/armeria/internal/common/AbstractKeepAliveHandler.java