Sending String from App > ESP32 > Arduino Mega. Works great unless loop() function is not empty. Then String is incomplete

I wanna control my Arduino Mega via an app on my mobile phone. Since the Mega has no WiFi/ Bluetooth, I use an ESP32 as interface. The idea is:
App sends String to ESP32 > ESP32 redirects String to Arduino Mega > Arduino Mega processes String
Basically I worked this out, but I ran into a problem later on, which I can't solve on my own. First let me show you my working code.
This is the code of the ESP32. I use these two libraries: ESPAsyncWebServer and AsyncTCP. To be honest, the code is largely based on an example I found online. I just changed the part, where it sends data to the second Serialport. I am not fully aware about whats going on here, but basically the ESP32 is a webserver and redirects the body of an request to Serial2, which is linked to the Arduino.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"

const char* ssid = "SSID_NAME"
const char* password = "PASSWORD"

AsyncWebServer server(80);
 
void setup() {
  Serial.begin(115200);
  Serial2.begin(115200);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
 
  Serial.println(WiFi.localIP());
 
  server.on(
    "/post",
    HTTP_POST,
    [](AsyncWebServerRequest * request){},
    NULL,
    [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {

      for (size_t i = 0; i < len; i++) {
        Serial.write(data[i]);
        Serial2.write((char) data[i]); // send data to Arduino Mega
        // Serial2.write(data[i]);
        // Serial2.print(data[i]);
      }
      Serial.println();
 
      request->send(200);
  });
 
  server.begin();
}
 
void loop() {
  }

Let me show you my first Arduino Code to prove the working concept.

void setup() {
    Serial.begin(115200);
    Serial1.begin(115200); // ESP32
}

void loop() {
    if (Serial1.available()) {
        Serial.println(Serial1.readString());

        // alternative:
        // String serialInput = Serial1.readString();
        // Serial.println(serialInput);
    }
}

This worked great, but soon I ran into a problem:
When I extended my loop() function, for example I added some led logic (I spare you the changes above the loop() function):

void loop() {
    if (Serial1.available()) {
        Serial.println(Serial1.readString());
    }

    if (digitalRead(LEFT_PIN) == LOW) {
        FastLED.showColor(CRGB::Blue);
    
    } else {
        FastLED.showColor(CRGB::Black);
  }
}

Suddenly I didnt get the correct strings anymore. There were charaters missing all the time. After some research I thought I would have to change the way I'm reading the incomming data, since Serial1.readString() is a blocking function.
I found the tutorial Serial Input Basics on this forum. (Sorry, I cant link it). I adapted the code of 'Example 3' and changed my app on the mobile phone, so it would send "<STRING>" instead of "STRING".
Let me show you my current Arduino code one last time. While the code for the led stuff is commented out, this approaches works flawless like the first one: Both, ESP32 and Arduino get the correct String.
As soon as I include the led code (I add somethng to the loop() function), I run into the same problems.

// Arduino Mega

#include "FastLED.h"

// LED
// #define NUM_LEDS 30
// #define LED_PIN 13
// #define HIGH_OR_LOW_PIN 46
// CRGB leds[NUM_LEDS];


const byte numChars = 32;
char receivedChars[numChars];

boolean newData = false;

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);

  // pinMode(HIGH_OR_LOW_PIN, INPUT);

  // FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
}

void loop() {
    recvWithStartEndMarkers();
    showNewData();

/*
  if (digitalRead(LEFT_PIN) == LOW) {
    FastLED.showColor(CRGB::Blue);
    
  } else {
    FastLED.showColor(CRGB::Black);
  }
*/ 
  
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (Serial1.available() > 0 && newData == false) {
   
        rc = Serial1.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

Here are some examples:
I send the String "<ABCDEFGHIJKLMNOPQRSTUVWXYZ>" with the app six times:
The ESP32 receives:

<ABCDEFGHIJKLMNOPQRSTUVWXYZ>
<ABCDEFGHIJKLMNOPQRSTUVWXYZ>
<ABCDEFGHIJKLMNOPQRSTUVWXYZ>
<ABCDEFGHIJKLMNOPQRSTUVWXYZ>
<ABCDEFGHIJKLMNOPQRSTUVWXYZ>
<ABCDEFGHIJKLMNOPQRSTUVWXYZ>

The Arduino prints:

This just in ... ABCDEFGHIJKLMVWXYZ
This just in ... ABCDEFGHIJKLMNOYZ
This just in ... ABCDEFGPQRSTUVWXYZ
This just in ... ABCDEFGHIJKUVWXYZ
This just in ... AFGHIJKLMNOPQRSTUVWXYZ
This just in ... ABCDEFGHQRSTUVWXYZ

I apologize for the many code blocks but I thought it was necessary to explain my problem. I hope somebody can take a look on it and help me.
I dont think its relevant, since the wiring should not be the problem, but ESP32 Serial2 is connected to Mega Serial1 via TX and RX (TX -> RX; RX -> TX) Yes, I use a logic shifter since the ESP32 operates with 3.3 V.
Have a great day!

Read this tutorial: Serial Input Basics - updated

It will show you how to receive data on your Mega if it is available and only act on it if a complete message has been received.

Thank you for your answer. I read the tutorial and I used the code from 'Example 3'. This is not the solution to solve my issue.

Slow down your ESP32 to Mega baud rate. It looks like you are overrunning the buffer. Difficult to receive and also report at the same baud as well as do other things.

WOW! Thank you! This seemed to work. I changed all baurates to 9600 and now the arduio receives the complete correct string. I thought both boards would be able to handle a rate of 115200. But since I see no performance difference I can stick with a rate of 9600. Thanks again!

at 9600 it takes a L-O-N-G time to send the message from the ESP32. If you hit the website too often (like 6 times in a row) the transmit buffer will fill up and the ESP32 will block until there is room to put the next message into the buffer.

In the meantime, the Mega now has 12x times longer to do things after receiving a message before the incoming buffer overflows (64 bytes)