diff --git a/src/nxt_conn_write.c b/src/nxt_conn_write.c index 7d0a579f2..2a92f0f5d 100644 --- a/src/nxt_conn_write.c +++ b/src/nxt_conn_write.c @@ -118,12 +118,8 @@ nxt_conn_io_write(nxt_task_t *task, void *obj, void *data) } } - if (ret == 0 || sb.sent != 0) { - /* - * ret == 0 means a sync buffer was processed. - * ret == NXT_ERROR is ignored here if some data was sent, - * the error will be handled on the next nxt_conn_write() call. - */ + if (ret == 0 || (ret != NXT_ERROR && sb.sent != 0)) { + /* ret == 0 means a sync buffer was processed. */ c->sent += sb.sent; nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, task, c, data); @@ -134,6 +130,21 @@ nxt_conn_io_write(nxt_task_t *task, void *obj, void *data) return; } + if (sb.sent != 0) { + /* + * Pattern D′: route to error_handler immediately when a write + * returns NXT_ERROR after a partial send (e.g. peer closed + * mid-response). Pre-fix, this case fell through to + * ready_handler and the error was deferred to the next + * nxt_conn_io_write() call via c->socket.error. Mirrors the + * TLS path's fail-fast contract; see nxt_openssl_conn_test_error. + */ + c->sent += sb.sent; + nxt_log(task, NXT_LOG_INFO, + "conn write: peer closed mid-response fd:%d sent:%O", + c->socket.fd, sb.sent); + } + nxt_fd_event_block_write(engine, &c->socket); error: diff --git a/src/nxt_router.c b/src/nxt_router.c index c994f3707..3f2161db7 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -5892,10 +5892,17 @@ nxt_router_get_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) nxt_assert(port->type == NXT_PROCESS_APP); if (nxt_slow_path(port->app == NULL)) { - nxt_alert(task, "get_mmap_handler: app == NULL for reply port %PI:%d", - port->pid, port->id); + /* + * Pattern D′: a NULL app pointer here is a benign race during + * worker shutdown / graceful reload (the app freed before its + * reply port was drained), not a corruption. Demoted from + * ALERT so reload-under-load doesn't pollute the log. + */ + nxt_log(task, NXT_LOG_INFO, + "get_mmap_handler: app == NULL for reply port %PI:%d " + "(peer likely shutting down)", + port->pid, port->id); - // FIXME nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1, msg->port_msg.stream, 0, NULL);