@@ -376,7 +376,15 @@ struct Sim2Conn final : IConnection, ReferenceCounted<Sim2Conn> {
376376 .detail (" StableConnection" , stableConnection);
377377 }
378378
379- ~Sim2Conn () { ASSERT_ABORT (!opened || closedByCaller); }
379+ ~Sim2Conn () {
380+ // Allow simulated HTTP server connections (either endpoint) to be destroyed without an explicit close.
381+ // These are managed by the HTTP server lifecycle and may not be closed by callers.
382+ const bool isHttpSide = g_simulator->httpServerIps .count (process->address .ip );
383+ const bool isHttpPeer = g_simulator->httpServerIps .count (peerEndpoint.ip );
384+ if (!(isHttpSide || isHttpPeer)) {
385+ ASSERT_ABORT (!opened || closedByCaller);
386+ }
387+ }
380388
381389 void addref () override { ReferenceCounted<Sim2Conn>::addref (); }
382390 void delref () override { ReferenceCounted<Sim2Conn>::delref (); }
@@ -497,6 +505,7 @@ struct Sim2Conn final : IConnection, ReferenceCounted<Sim2Conn> {
497505 ACTOR static Future<Void> sender (Sim2Conn* self) {
498506 loop {
499507 wait (self->writtenBytes .onChange ()); // takes place on peer!
508+ wait (g_simulator->onProcess (self->peerProcess ));
500509 ASSERT (g_simulator->getCurrentProcess () == self->peerProcess );
501510 wait (delay (.002 * deterministicRandom ()->random01 ()));
502511 self->sentBytes .set (self->writtenBytes .get ()); // or possibly just some sometimes...
@@ -539,41 +548,53 @@ struct Sim2Conn final : IConnection, ReferenceCounted<Sim2Conn> {
539548 }
540549 }
541550 ACTOR static Future<Void> whenReadable (Sim2Conn* self) {
542- try {
543- loop {
551+ loop {
552+ wait (g_simulator->onProcess (self->process ));
553+ try {
544554 if (self->readBytes .get () != self->receivedBytes .get ()) {
545- ASSERT (g_simulator->getCurrentProcess () == self->process );
555+ if (g_simulator->getCurrentProcess () != self->process ) {
556+ return Void ();
557+ }
546558 return Void ();
547559 }
548560 wait (self->receivedBytes .onChange ());
549561 self->rollRandomClose ();
562+ } catch (Error& e) {
563+ if (g_simulator->getCurrentProcess () != self->process ) {
564+ return Void ();
565+ }
566+ throw ;
550567 }
551- } catch (Error& e) {
552- ASSERT (g_simulator->getCurrentProcess () == self->process );
553- throw ;
554568 }
555569 }
556570 ACTOR static Future<Void> whenWritable (Sim2Conn* self) {
557- try {
558- loop {
559- if (!self->peer )
560- return Void ();
571+ loop {
572+ if (!self->peer )
573+ return Void ();
574+ wait (g_simulator->onProcess (self->process ));
575+ try {
561576 if (self->peer ->availableSendBufferForPeer () > 0 ) {
562- ASSERT (g_simulator->getCurrentProcess () == self->process );
577+ if (g_simulator->getCurrentProcess () != self->process ) {
578+ return Void ();
579+ }
563580 return Void ();
564581 }
565582 try {
566583 wait (self->peer ->receivedBytes .onChange ());
567- ASSERT (g_simulator->getCurrentProcess () == self->peerProcess );
584+ wait (g_simulator->onProcess (self->peerProcess ));
585+ if (g_simulator->getCurrentProcess () != self->peerProcess ) {
586+ return Void ();
587+ }
568588 } catch (Error& e) {
569589 if (e.code () != error_code_broken_promise)
570590 throw ;
571591 }
572- wait (g_simulator->onProcess (self->process ));
592+ } catch (Error& e) {
593+ if (g_simulator->getCurrentProcess () != self->process ) {
594+ return Void ();
595+ }
596+ throw ;
573597 }
574- } catch (Error& e) {
575- ASSERT (g_simulator->getCurrentProcess () == self->process );
576- throw ;
577598 }
578599 }
579600
@@ -1857,6 +1878,13 @@ class Sim2 final : public ISimulator, public INetworkConnections {
18571878 .detail (" Address" , p->address )
18581879 .detail (" MachineId" , p->locality .machineId ());
18591880 currentlyRebootingProcesses.insert (std::pair<NetworkAddress, ProcessInfo*>(p->address , p));
1881+
1882+ // Safety check to prevent Optional assertion failure
1883+ if (!p->locality .machineId ().present ()) {
1884+ TraceEvent (" Sim2DestroyProcessNoMachineId" ).detail (" Name" , p->name ).detail (" Address" , p->address );
1885+ return ;
1886+ }
1887+
18601888 std::vector<ProcessInfo*>& processes = machines[p->locality .machineId ().get ()].processes ;
18611889 machines[p->locality .machineId ().get ()].removeRemotePort (p->address .port );
18621890 if (p != processes.back ()) {
@@ -2596,6 +2624,34 @@ class Sim2 final : public ISimulator, public INetworkConnections {
25962624 return registerSimHTTPServerActor (this , hostname, service, requestHandler);
25972625 }
25982626
2627+ ACTOR static Future<Void> unregisterSimHTTPServerActor (Sim2* self, std::string hostname, std::string service) {
2628+ std::string id = hostname + " :" + service;
2629+ state std::unordered_map<std::string, Reference<HTTP::SimRegisteredHandlerContext>>::iterator handlerIt =
2630+ self->httpHandlers .find (id);
2631+ if (handlerIt == self->httpHandlers .end ()) {
2632+ return Void ();
2633+ }
2634+ // Copy processes to avoid races
2635+ state std::vector<std::pair<ProcessInfo*, Reference<HTTP::SimServerContext>>> procsCopy =
2636+ self->httpServerProcesses ;
2637+ state int i = 0 ;
2638+ for (; i < procsCopy.size (); i++) {
2639+ state ProcessInfo* serverProcess = procsCopy[i].first ;
2640+ wait (self->onProcess (serverProcess, TaskPriority::DefaultYield));
2641+ handlerIt->second ->removeIp (serverProcess->address .ip );
2642+ // Stop the HTTP server listeners to ensure connections are torn down
2643+ procsCopy[i].second ->stop ();
2644+ }
2645+ self->httpHandlers .erase (handlerIt);
2646+ return Void ();
2647+ }
2648+
2649+ Future<Void> unregisterSimHTTPServer (std::string hostname, std::string service) override {
2650+ return unregisterSimHTTPServerActor (this , hostname, service);
2651+ }
2652+
2653+ // TODO: Unregister will be added in a follow-up change
2654+
25992655 Sim2 (bool printSimTime)
26002656 : time(0.0 ), timerTime(0.0 ), currentTaskID(TaskPriority::Zero), yielded(false ), yield_limit(0 ),
26012657 printSimTime (printSimTime) {
@@ -2733,6 +2789,10 @@ class UDPSimSocket : public IUDPSocket, ReferenceCounted<UDPSimSocket> {
27332789 Future<Void> onClosed () const { return closed.getFuture (); }
27342790
27352791 ACTOR static Future<Void> cleanupPeerSocket (UDPSimSocket* self) {
2792+ // Safety check to prevent Optional assertion failure
2793+ if (!self->peerSocket .present ()) {
2794+ return Void ();
2795+ }
27362796 wait (self->peerSocket .get ()->onClosed ());
27372797 self->peerSocket .reset ();
27382798 return Void ();
@@ -2803,6 +2863,12 @@ class UDPSimSocket : public IUDPSocket, ReferenceCounted<UDPSimSocket> {
28032863 }
28042864 if (!peerSocket.present () || peerSocket.get ()->isClosed ()) {
28052865 peerSocket.reset ();
2866+
2867+ // Safety check to prevent Optional assertion failure
2868+ if (!peerProcess.present ()) {
2869+ return res;
2870+ }
2871+
28062872 auto iter = peerProcess.get ()->boundUDPSockets .find (peerAddress.get ());
28072873 if (iter == peerProcess.get ()->boundUDPSockets .end ()) {
28082874 return fmap ([sz](Void) { return sz; }, delay (0.0 ));
0 commit comments