31 同步消费、收据与未来 MDB/死信:实验合同 现行入口:examples/javaee-enterprise/webapp/src/main/java/blog/javaee/web/BrokerLabResource.java 的 receiveOne/recordReceipt;db/migrations/003-notification-receipt.sql;scenarios/30-broker-lab.sh。Liberty 26.0.0.5 内嵌持久队列,JMSContext.SESSION_TRANSACTED 同步接收;notification_receipt(event_id PRIMARY KEY, tenant_id, received_at) 是数据库收据,没有供应商效果/真实邮件,也没有 MDB、失败归档或毒消息策略。 先完成独立 javaee_lab 数据库的 001、002、003 迁移,依照 examples/javaee-enterprise/README.md 在回环部署 deploy/server-messaging.xml 对应 WAR(JDK 21.0.12.1、PostgreSQL 16.15、pgJDBC 42.7.7、Maven wrapper、curl/jq/psql)。只在 JAVAEE_DEMO_MODE=true 的本地隔离环境执行;不能把 X-Lab-Tenant 作为身份。运行: cd examples/javaee-enterprise ../hibernate-lab/mvnw -B -ntp -f "$PWD/pom.xml" clean verify JAVAEE_PORT=9085 JAVAEE_DEMO_MODE=true JAVAEE_LAB_USER=javaee_lab JAVAEE_LAB_PASSWORD='<本机真实口令>' bash scenarios/30-broker-lab.sh 正常/失败判据:场景订单生成一个 event;receive-one?abortAfterRecord=true 先持久写收据,再回滚 JMS 并返回预期 HTTP 500;十次有界尝试内同一 event 再次接收返回 HTTP 200、newReceipt=false,场景退出 0。脚本在回滚后断言 SQL 收据为 1;末尾打印 receipt_unchanged,但不对最后一次计数断言,须人工核实为 |PUBLISHED|1。若 ID 不符、收据变化、未见同 ID 消息或异常 HTTP 不是预期 500,不能判通过(其中末次收据变化不一定令脚本退出非零)。脚本还覆盖发送侧两次发送,未保存 JMSMessageID,不能判断后一次是同一物理消息的重投还是第二条首次交付;也不代表 MDB 故障屏障或对端副作用。保留原始 stdout/stderr/退出码、部署 WAR 哈希、数据库输出与日志。writing-plans/javaee-enterprise/verification/20261004T-broker-lab/RUN.md 记录当时 event 5 和场景退出 0;receive-after-restart.body.txt 记录脚本外独立重启后再次同步接收 newReceipt=false、HTTP 200;不是脚本内杀进程。 FUTURE/NOT_RUN:需要先选定并冻结 MDB 激活配置、事务参与方式及实际重投次数/失败地址,再实现毒消息与归档人工重放;没有真实可执行的 scenarios/31-consumer.sh。测试应分别区分收据写入后 JMS rollback、容器事务回滚和进程强停,检查真实消息 ID 对应稳定 event ID、队列/归档终态、收据行数与外部效果。当前 003 无 payload_hash/effect_type,不能宣称具备业务效果至多一次或死信功能。规范 Jakarta Messaging 3.1:https://jakarta.ee/specifications/messaging/3.1/jakarta-messaging-spec-3.1;Jakarta Enterprise Beans 4.0:https://jakarta.ee/specifications/enterprise-beans/4.0/jakarta-enterprise-beans-spec-core-4.0。