# Motoko function doesn't complete

**URL:** <https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334>\
**Category:** Language Support\
**Tags:** Motoko\
**Created:** [August 20, 2024, 1:33pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334 "2024-08-20T13:33:46Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 1:33pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/1 "2024-08-20T13:33:46Z")

</div>

I’m trying to run a function to clean some teams involving looping over the manager records, updating them and then saving. It works locally. However on live the function doesn’t get to the end, I confirm the following via logs when the function runs:

I have 313 managers to loop over:

![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/8/1/8116c93d238e91e5c281d76f4aece94b1665945d.png)

Here is the function:

```auto

  private func cleanManagerTeams(managers : [T.Manager], allPlayers : [DTOs.PlayerDTO]) : async [T.Manager] {
    let managerBuffer = Buffer.fromArray<T.Manager>([]);

    await logStatus("Cleaning " # Nat.toText(Array.size(managers)) # " teams.");
    for (manager in Iter.fromArray(managers)) {
      var captainRemoved = false;
      let playerIdBuffer = Buffer.fromArray<T.PlayerId>([]);
      for (playerId in Iter.fromArray(manager.playerIds)) {
        
        let activePlayer = Array.find<DTOs.PlayerDTO>(allPlayers, func(player: DTOs.PlayerDTO){
          player.id == playerId
        });

        if(Option.isSome(activePlayer)){
          playerIdBuffer.add(playerId);
        };

        if(Option.isNull(activePlayer)){
          if(playerId == manager.captainId){
            captainRemoved := true;
          };
          playerIdBuffer.add(0);
        };
      };

      var captainId = manager.captainId;
      if(captainRemoved){
        let highestValuedPlayer = Array.foldLeft<T.PlayerId, ?DTOs.PlayerDTO>(
          Buffer.toArray(playerIdBuffer),
          null,
          func(highest, id) : ?DTOs.PlayerDTO {
            if (id == 0) { return highest };
            let player = Array.find<DTOs.PlayerDTO>(allPlayers, func(p) { p.id == id });
            switch (highest, player) {
              case (null, ?p) {
                ?p;
              };
              case (?h, ?p) {
                if (p.valueQuarterMillions > h.valueQuarterMillions) {
                  ?p;
                } else {
                  ?h;
                };
              };
              case (_, null) {
                highest;
              };
            };
          },
        );
        switch(highestValuedPlayer){
          case (?foundPlayer){
            captainId := foundPlayer.id;
          };
          case (null){}
        };
      };

      var updatedPlayerIds = Buffer.toArray(playerIdBuffer);

      let allTeamPlayers = Array.filter<DTOs.PlayerDTO>(allPlayers, func(player: DTOs.PlayerDTO){
        Array.find<T.PlayerId>(updatedPlayerIds, func(playerId){
          playerId == player.id
        }) != null;
      });

      let allPlayerValues = Array.map<DTOs.PlayerDTO, Nat16>(allTeamPlayers, func (player: DTOs.PlayerDTO) : Nat16 { return player.valueQuarterMillions; });

      let currentTeamValue = Array.foldLeft<Nat16, Nat16>(allPlayerValues, 0, func(sumSoFar, x) = sumSoFar + x);

      var arrstr = "";
      for(id in Iter.fromArray(manager.playerIds)){
        arrstr := arrstr # Nat16.toText(id) # ",";
      };
      
      await logStatus("Team value for " # manager.principalId # "is " # Nat16.toText(currentTeamValue) # ", " # arrstr);
      if(currentTeamValue > 1200){
        await logStatus("Team " # manager.principalId # " has a team over 300m.");
      };

      var bankBalance: Nat16 = 0;
      var testBalance: Int = 1200 - Int16.toInt(Int16.fromNat16(currentTeamValue));
      if(testBalance >= 0){
        bankBalance := Nat16.fromIntWrap(testBalance);
      };

      if(testBalance < 0){
        updatedPlayerIds := [];
        bankBalance := 1200;
      };
      
      let updatedManager : T.Manager = {
        principalId = manager.principalId;
        username = manager.username;
        termsAccepted = manager.termsAccepted;
        favouriteClubId = manager.favouriteClubId;
        createDate = manager.createDate;
        history = manager.history;
        profilePicture = manager.profilePicture;
        profilePictureType = manager.profilePictureType;
        transfersAvailable = manager.transfersAvailable;
        monthlyBonusesAvailable = manager.monthlyBonusesAvailable;
        bankQuarterMillions = bankBalance;
        playerIds = updatedPlayerIds;
        captainId = captainId;
        goalGetterGameweek = manager.goalGetterGameweek;
        goalGetterPlayerId = manager.goalGetterPlayerId;
        passMasterGameweek = manager.passMasterGameweek;
        passMasterPlayerId = manager.passMasterPlayerId;
        noEntryGameweek = manager.noEntryGameweek;
        noEntryPlayerId = manager.noEntryPlayerId;
        teamBoostGameweek = manager.teamBoostGameweek;
        teamBoostClubId = manager.teamBoostClubId;
        safeHandsGameweek = manager.safeHandsGameweek;
        safeHandsPlayerId = manager.safeHandsPlayerId;
        captainFantasticGameweek = manager.captainFantasticGameweek;
        captainFantasticPlayerId = manager.captainFantasticPlayerId;
        countrymenGameweek = manager.countrymenGameweek;
        countrymenCountryId = manager.countrymenCountryId;
        prospectsGameweek = manager.prospectsGameweek;
        braceBonusGameweek = manager.braceBonusGameweek;
        hatTrickHeroGameweek = manager.hatTrickHeroGameweek;
        transferWindowGameweek = manager.transferWindowGameweek;
        ownedPrivateLeagues = manager.ownedPrivateLeagues;
        privateLeagueMemberships = manager.privateLeagueMemberships;
      };
      managerBuffer.add(updatedManager);
    };
    return Buffer.toArray(managerBuffer);
  };

```

As you can see I check by logging the team value that it loops through everyone and I get 313 log records:

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/e/9/e99b6abc213b901e6206e99755fdbf0a2154bfb3.jpeg)

After this function completes its execution I have another log statement immediately after, which only executes on local, for some reason this function doesn’t complete after the final loop where it logs the team value.

The complete file is here:

> <https://github.com/jamesbeadle/OpenFPL/blob/master/src/OpenFPL_backend/canister_definitions/manager-canister.mo>

Any help appreciated.

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 1:42pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/2 "2024-08-20T13:42:41Z")

</div>

Since it bugs out on live, which has more managers and it happens just before the function completes, it makes me think returning the buffer of 300+ managers is too large, is there a limit for calls returned between functions inside an actor?

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 4:22pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/3 "2024-08-20T16:22:05Z")

</div>

More debugging, so I call this:

```auto

    public func cleanFantasyTeams() : async (){
      for (canisterId in Iter.fromList(uniqueManagerCanisterIds)) {
        let manager_canister = actor (canisterId) : actor {
          cleanFantasyTeams : () -> async ();
        };

        await manager_canister.cleanFantasyTeams();

        logStatus("Clean fantasy teams end from manager composite.");
      };
    };

```

which calls out to the manager canister:

```auto

  public shared ({ caller }) func cleanFantasyTeams() : async () {

    assert not Principal.isAnonymous(caller);
    let principalId = Principal.toText(caller);
    assert principalId == Environment.BACKEND_CANISTER_ID;

    let openfpl_backend_canister = actor (Environment.BACKEND_CANISTER_ID) : actor {
      getActivePlayers : () -> async [DTOs.PlayerDTO];
    };
    let allPlayers : [DTOs.PlayerDTO] = await openfpl_backend_canister.getActivePlayers();

    if(Array.size(allPlayers) == 0){
      return;
    };

    for (index in Iter.range(0, 11)) {
      switch (index) {
        case 0 {
          managerGroup1 := await cleanManagerTeams(managerGroup1, allPlayers);
        };
        case 1 {
          managerGroup2 := await cleanManagerTeams(managerGroup2, allPlayers);
        };
        case 2 {
          managerGroup3 := await cleanManagerTeams(managerGroup3, allPlayers);
        };
        case 3 {
          managerGroup4 := await cleanManagerTeams(managerGroup4, allPlayers);
        };
        case 4 {
          managerGroup5 := await cleanManagerTeams(managerGroup5, allPlayers);
        };
        case 5 {
          managerGroup6 := await cleanManagerTeams(managerGroup6, allPlayers);
        };
        case 6 {
          managerGroup7 := await cleanManagerTeams(managerGroup7, allPlayers);
        };
        case 7 {
          managerGroup8 := await cleanManagerTeams(managerGroup8, allPlayers);
        };
        case 8 {
          managerGroup9 := await cleanManagerTeams(managerGroup9, allPlayers);
        };
        case 9 {
          managerGroup10 := await cleanManagerTeams(managerGroup10, allPlayers);
        };
        case 10 {
          managerGroup11 := await cleanManagerTeams(managerGroup11, allPlayers);
        };
        case 11 {
          managerGroup12 := await cleanManagerTeams(managerGroup12, allPlayers);
        };
        case _ {

        };
      };
    };
  };

  private func cleanManagerTeams(managers : [T.Manager], allPlayers : [DTOs.PlayerDTO]) : async [T.Manager] {
    let managerBuffer = Buffer.fromArray<T.Manager>([]);

    await logStatus("Cleaning " # Nat.toText(Array.size(managers)) # " teams.");
    for (manager in Iter.fromArray(managers)) {
      var captainRemoved = false;
      let playerIdBuffer = Buffer.fromArray<T.PlayerId>([]);
      for (playerId in Iter.fromArray(manager.playerIds)) {
        
        let activePlayer = Array.find<DTOs.PlayerDTO>(allPlayers, func(player: DTOs.PlayerDTO){
          player.id == playerId
        });

        if(Option.isSome(activePlayer)){
          playerIdBuffer.add(playerId);
        };

        if(Option.isNull(activePlayer)){
          if(playerId == manager.captainId){
            captainRemoved := true;
          };
          playerIdBuffer.add(0);
        };
      };

      var captainId = manager.captainId;
      if(captainRemoved){
        let highestValuedPlayer = Array.foldLeft<T.PlayerId, ?DTOs.PlayerDTO>(
          Buffer.toArray(playerIdBuffer),
          null,
          func(highest, id) : ?DTOs.PlayerDTO {
            if (id == 0) { return highest };
            let player = Array.find<DTOs.PlayerDTO>(allPlayers, func(p) { p.id == id });
            switch (highest, player) {
              case (null, ?p) {
                ?p;
              };
              case (?h, ?p) {
                if (p.valueQuarterMillions > h.valueQuarterMillions) {
                  ?p;
                } else {
                  ?h;
                };
              };
              case (_, null) {
                highest;
              };
            };
          },
        );
        switch(highestValuedPlayer){
          case (?foundPlayer){
            captainId := foundPlayer.id;
          };
          case (null){}
        };
      };

      var updatedPlayerIds = Buffer.toArray(playerIdBuffer);

      let allTeamPlayers = Array.filter<DTOs.PlayerDTO>(allPlayers, func(player: DTOs.PlayerDTO){
        Array.find<T.PlayerId>(updatedPlayerIds, func(playerId){
          playerId == player.id
        }) != null;
      });

      let allPlayerValues = Array.map<DTOs.PlayerDTO, Nat16>(allTeamPlayers, func (player: DTOs.PlayerDTO) : Nat16 { return player.valueQuarterMillions; });

      let currentTeamValue = Array.foldLeft<Nat16, Nat16>(allPlayerValues, 0, func(sumSoFar, x) = sumSoFar + x);

      var arrstr = "";
      for(id in Iter.fromArray(manager.playerIds)){
        arrstr := arrstr # Nat16.toText(id) # ",";
      };
      
      await logStatus("Team value for " # manager.principalId # "is " # Nat16.toText(currentTeamValue) # ", " # arrstr);
      if(currentTeamValue > 1200){
        await logStatus("Team " # manager.principalId # " has a team over 300m.");
      };

      var bankBalance: Nat16 = 0;
      var testBalance: Int = 1200 - Int16.toInt(Int16.fromNat16(currentTeamValue));
      if(testBalance >= 0){
        bankBalance := Nat16.fromIntWrap(testBalance);
      };

      if(testBalance < 0){
        updatedPlayerIds := [];
        bankBalance := 1200;
      };
        await logStatus("Adding updated " # manager.principalId # " to manager array.");
      
      let updatedManager : T.Manager = {
        principalId = manager.principalId;
        username = manager.username;
        termsAccepted = manager.termsAccepted;
        favouriteClubId = manager.favouriteClubId;
        createDate = manager.createDate;
        history = manager.history;
        profilePicture = manager.profilePicture;
        profilePictureType = manager.profilePictureType;
        transfersAvailable = manager.transfersAvailable;
        monthlyBonusesAvailable = manager.monthlyBonusesAvailable;
        bankQuarterMillions = bankBalance;
        playerIds = updatedPlayerIds;
        captainId = captainId;
        goalGetterGameweek = manager.goalGetterGameweek;
        goalGetterPlayerId = manager.goalGetterPlayerId;
        passMasterGameweek = manager.passMasterGameweek;
        passMasterPlayerId = manager.passMasterPlayerId;
        noEntryGameweek = manager.noEntryGameweek;
        noEntryPlayerId = manager.noEntryPlayerId;
        teamBoostGameweek = manager.teamBoostGameweek;
        teamBoostClubId = manager.teamBoostClubId;
        safeHandsGameweek = manager.safeHandsGameweek;
        safeHandsPlayerId = manager.safeHandsPlayerId;
        captainFantasticGameweek = manager.captainFantasticGameweek;
        captainFantasticPlayerId = manager.captainFantasticPlayerId;
        countrymenGameweek = manager.countrymenGameweek;
        countrymenCountryId = manager.countrymenCountryId;
        prospectsGameweek = manager.prospectsGameweek;
        braceBonusGameweek = manager.braceBonusGameweek;
        hatTrickHeroGameweek = manager.hatTrickHeroGameweek;
        transferWindowGameweek = manager.transferWindowGameweek;
        ownedPrivateLeagues = manager.ownedPrivateLeagues;
        privateLeagueMemberships = manager.privateLeagueMemberships;
      };
      managerBuffer.add(updatedManager);
    };
        
    await logStatus("All snapshots have been taken and the function is returning ." # Nat.toText(Array.size(Buffer.toArray(managerBuffer))));
    return Buffer.toArray(managerBuffer);
  };

```

As you can see I’ve done a lot of logging but from this screenshot you can see it reaches the end of the cleanManagerTeams function:

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/9/3/93b04c28aeb60b9f728e3fd70b168d7811de182d.jpeg)

But it doesn’t log the statement after the call to manager\_canister.cleanFantasyTeams, but I’m not sure if/where it has trapped to not print:

```auto
logStatus("Clean fantasy teams end from manager composite.");

```

---

<div class="post-metadata">

**Author:** ![v1ctor](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/v1ctor/32/9360_2.png) [@v1ctor](https://forum.dfinity.org/u/v1ctor)\
**Post date:** [August 20, 2024, 4:31pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/4 "2024-08-20T16:31:40Z")

</div>

If I’m not mistaken, in Motoko you must at least use “ignore” when calling async methods (assuming logStatus is async).

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 4:35pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/5 "2024-08-20T16:35:35Z")

</div>

I get this when I use ignore on it:

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/7/2/72a0f561edeaa76ae4387c4e4893830c2ab1d93a.png)

As I said, locally this function completes. Could it be something to do with subnets, I’m assuming locally my canisters are on the same subnet but live they may not be.

For some reason on live the call to the manager canister just doesn’t return to continue the fix.

---

<div class="post-metadata">

**Author:** ![v1ctor](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/v1ctor/32/9360_2.png) [@v1ctor](https://forum.dfinity.org/u/v1ctor)\
**Post date:** [August 20, 2024, 4:46pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/6 "2024-08-20T16:46:36Z")

</div>

> [@jamesbeadle](#):
>
> `logStatus`

What happens if you change it to

```auto
    ignore logStatus("Clean fantasy teams end from manager composite.");
```

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 4:48pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/7 "2024-08-20T16:48:11Z")

</div>

Yes that works syntax wise.

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/8/2/822c7e0f5fd5e6e1a6794415c44625db20f5c6d5.png)

So the logging is the issue? or is it any await call to a different canister?

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 4:51pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/8 "2024-08-20T16:51:47Z")

</div>

So in the manager canister I can update the log which calls out to the backend (the backend the function isn’t returning to) to use ignore:

```auto

  private func logStatus(statusMessage: Text) : async (){
    let openfpl_backend_canister = actor (Environment.BACKEND_CANISTER_ID) : actor {
      logStatus : (DTOs.LogStatusDTO) -> async ();
    };
    ignore openfpl_backend_canister.logStatus({ message = statusMessage; });
  };

```

But within this calculation I make other await calls, some again to the backend canister to get information like player info:

```auto
 let openfpl_backend_canister = actor (Environment.BACKEND_CANISTER_ID) : actor {
      getActivePlayers : () -> async [DTOs.PlayerDTO];
    };
    let allPlayers : [DTOs.PlayerDTO] = await openfpl_backend_canister.getActivePlayers();

```

I’m not 100% sure when I should be using ignore and when I should await the result of something I need.

---

<div class="post-metadata">

**Author:** ![v1ctor](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/v1ctor/32/9360_2.png) [@v1ctor](https://forum.dfinity.org/u/v1ctor)\
**Post date:** [August 20, 2024, 5:04pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/9 "2024-08-20T17:04:50Z")

</div>

For logging I always used ignore in Motoko when doing an async call as you don’t need to be sure if it trapped or not (even if logging failed, your main canister should not fail).

For everything else that needs to be confirmed, even without an explicit return value, I await’ed the call inside a try … catch block to treat any trap/exception and revert the transaction if needed.

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 5:10pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/10 "2024-08-20T17:10:23Z")

</div>

I tried ignoring the log statement when calling back to the canister I get the same problem. I call the last line of clearManagerTeams:

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/c/0/c063a93d112ab645c6babfd94fa46488dfc3874d.png)

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/e/2/e24167df9ee5356b8ca12b0c6b7f0a3dcdbc12e5.jpeg)

But it still doesn’t return the array and move onto the next group:

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/8/1/81869d0171eb34cb050008c60f2de7bb242477d5.png)

Do you have any idea what I could do to debug between the end of the loop and the start of the next value? I feel like I’m missing something obvious as on local it goes through each of the 12 manager groups without issue.

---

<div class="post-metadata">

**Author:** ![v1ctor](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/v1ctor/32/9360_2.png) [@v1ctor](https://forum.dfinity.org/u/v1ctor)\
**Post date:** [August 20, 2024, 5:43pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/11 "2024-08-20T17:43:55Z")

</div>

I would try to log the length of managerGroup# before and after calls and the index value.

But if it works locally, I guess the local data isn’t the same as in production, right? I would try to dump the production data and load it locally to debug.

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 5:48pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/12 "2024-08-20T17:48:20Z")

</div>

> [@v1ctor](#):
>
> mangerGroup

Yeah I do that on the last line of the log

```
await logStatus("All snapshots have been taken and the function is returning ." # Nat.toText(Array.size(Buffer.toArray(managerBuffer))));

```

Ignore the full stop before the number, that is 313 managers.

Is there a reason for knowing the number, because there is some data size limit on function to function array size transfers?

---

<div class="post-metadata">

**Author:** ![v1ctor](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/v1ctor/32/9360_2.png) [@v1ctor](https://forum.dfinity.org/u/v1ctor)\
**Post date:** [August 20, 2024, 6:23pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/13 "2024-08-20T18:23:51Z")

</div>

It would trap if going over the 2MB response size limit.

Are you testing locally with the same data present in production?

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 6:27pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/14 "2024-08-20T18:27:32Z")

</div>

I’m not transferring 2MB out of the canister, it’s setting a stable variable in the canister. But that’s 2MB for any response. Let’s say all 313 had a profile picture, I’d be trying to update around 150 MB of data.

So I just need to update individually, but I can hold the 150mb in memory inside the function? I’d need to for the stable managerGroup1 update…

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 6:38pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/15 "2024-08-20T18:38:55Z")

</div>

So this is refactored to not transfer any large data outside of the function that is running:

```auto

  public shared ({ caller }) func cleanFantasyTeams() : async () {

    assert not Principal.isAnonymous(caller);
    let principalId = Principal.toText(caller);
    assert principalId == Environment.BACKEND_CANISTER_ID;

    let openfpl_backend_canister = actor (Environment.BACKEND_CANISTER_ID) : actor {
      getActivePlayers : () -> async [DTOs.PlayerDTO];
    };
    let allPlayers : [DTOs.PlayerDTO] = await openfpl_backend_canister.getActivePlayers();

    if(Array.size(allPlayers) == 0){
      return;
    };

    for (index in Iter.range(0, 11)) {
      await cleanManagerTeams(index, allPlayers);
    };
  };

  private func cleanManagerTeams(managerGroup: Int, allPlayers : [DTOs.PlayerDTO]) : async () {
    let managerBuffer = Buffer.fromArray<T.Manager>([]);

    var managers: [T.Manager] = [];

    switch (managerGroup) {
      case 0 {
        managers := managerGroup1;
      };
      case 1 {
        managers := managerGroup2;
      };
      case 2 {
        managers := managerGroup3;
      };
      case 3 {
        managers := managerGroup4;
      };
      case 4 {
        managers := managerGroup5;
      };
      case 5 {
        managers := managerGroup6;
      };
      case 6 {
        managers := managerGroup7;
      };
      case 7 {
        managers := managerGroup8;
      };
      case 8 {
        managers := managerGroup9;
      };
      case 9 {
        managers := managerGroup10;
      };
      case 10 {
        managers := managerGroup11;
      };
      case 11 {
        managers := managerGroup12;
      };
      case _ {

      };
    };

    await logStatus("Cleaning " # Nat.toText(Array.size(managers)) # " teams.");
    for (manager in Iter.fromArray(managers)) {
      var captainRemoved = false;
      let playerIdBuffer = Buffer.fromArray<T.PlayerId>([]);
      for (playerId in Iter.fromArray(manager.playerIds)) {
        
        let activePlayer = Array.find<DTOs.PlayerDTO>(allPlayers, func(player: DTOs.PlayerDTO){
          player.id == playerId
        });

        if(Option.isSome(activePlayer)){
          playerIdBuffer.add(playerId);
        };

        if(Option.isNull(activePlayer)){
          if(playerId == manager.captainId){
            captainRemoved := true;
          };
          playerIdBuffer.add(0);
        };
      };

      var captainId = manager.captainId;
      if(captainRemoved){
        let highestValuedPlayer = Array.foldLeft<T.PlayerId, ?DTOs.PlayerDTO>(
          Buffer.toArray(playerIdBuffer),
          null,
          func(highest, id) : ?DTOs.PlayerDTO {
            if (id == 0) { return highest };
            let player = Array.find<DTOs.PlayerDTO>(allPlayers, func(p) { p.id == id });
            switch (highest, player) {
              case (null, ?p) {
                ?p;
              };
              case (?h, ?p) {
                if (p.valueQuarterMillions > h.valueQuarterMillions) {
                  ?p;
                } else {
                  ?h;
                };
              };
              case (_, null) {
                highest;
              };
            };
          },
        );
        switch(highestValuedPlayer){
          case (?foundPlayer){
            captainId := foundPlayer.id;
          };
          case (null){}
        };
      };

      var updatedPlayerIds = Buffer.toArray(playerIdBuffer);

      let allTeamPlayers = Array.filter<DTOs.PlayerDTO>(allPlayers, func(player: DTOs.PlayerDTO){
        Array.find<T.PlayerId>(updatedPlayerIds, func(playerId){
          playerId == player.id
        }) != null;
      });

      let allPlayerValues = Array.map<DTOs.PlayerDTO, Nat16>(allTeamPlayers, func (player: DTOs.PlayerDTO) : Nat16 { return player.valueQuarterMillions; });

      let currentTeamValue = Array.foldLeft<Nat16, Nat16>(allPlayerValues, 0, func(sumSoFar, x) = sumSoFar + x);

      var arrstr = "";
      for(id in Iter.fromArray(manager.playerIds)){
        arrstr := arrstr # Nat16.toText(id) # ",";
      };
      
      await logStatus("Team value for " # manager.principalId # "is " # Nat16.toText(currentTeamValue) # ", " # arrstr);
      if(currentTeamValue > 1200){
        await logStatus("Team " # manager.principalId # " has a team over 300m.");
      };

      var bankBalance: Nat16 = 0;
      var testBalance: Int = 1200 - Int16.toInt(Int16.fromNat16(currentTeamValue));
      if(testBalance >= 0){
        bankBalance := Nat16.fromIntWrap(testBalance);
      };

      if(testBalance < 0){
        updatedPlayerIds := [];
        bankBalance := 1200;
      };
        await logStatus("Adding updated " # manager.principalId # " to manager array.");
      
      let updatedManager : T.Manager = {
        principalId = manager.principalId;
        username = manager.username;
        termsAccepted = manager.termsAccepted;
        favouriteClubId = manager.favouriteClubId;
        createDate = manager.createDate;
        history = manager.history;
        profilePicture = manager.profilePicture;
        profilePictureType = manager.profilePictureType;
        transfersAvailable = manager.transfersAvailable;
        monthlyBonusesAvailable = manager.monthlyBonusesAvailable;
        bankQuarterMillions = bankBalance;
        playerIds = updatedPlayerIds;
        captainId = captainId;
        goalGetterGameweek = manager.goalGetterGameweek;
        goalGetterPlayerId = manager.goalGetterPlayerId;
        passMasterGameweek = manager.passMasterGameweek;
        passMasterPlayerId = manager.passMasterPlayerId;
        noEntryGameweek = manager.noEntryGameweek;
        noEntryPlayerId = manager.noEntryPlayerId;
        teamBoostGameweek = manager.teamBoostGameweek;
        teamBoostClubId = manager.teamBoostClubId;
        safeHandsGameweek = manager.safeHandsGameweek;
        safeHandsPlayerId = manager.safeHandsPlayerId;
        captainFantasticGameweek = manager.captainFantasticGameweek;
        captainFantasticPlayerId = manager.captainFantasticPlayerId;
        countrymenGameweek = manager.countrymenGameweek;
        countrymenCountryId = manager.countrymenCountryId;
        prospectsGameweek = manager.prospectsGameweek;
        braceBonusGameweek = manager.braceBonusGameweek;
        hatTrickHeroGameweek = manager.hatTrickHeroGameweek;
        transferWindowGameweek = manager.transferWindowGameweek;
        ownedPrivateLeagues = manager.ownedPrivateLeagues;
        privateLeagueMemberships = manager.privateLeagueMemberships;
      };
      managerBuffer.add(updatedManager);
    };
        
    await logStatus("All snapshots have been taken and the function is returning ." # Nat.toText(Array.size(Buffer.toArray(managerBuffer))));
    
    switch (managerGroup) {
      case 0 {
        managerGroup1 := Buffer.toArray(managerBuffer);
      };
      case 1 {
        managerGroup2 := Buffer.toArray(managerBuffer);
      };
      case 2 {
        managerGroup3 := Buffer.toArray(managerBuffer);
      };
      case 3 {
        managerGroup4 := Buffer.toArray(managerBuffer);
      };
      case 4 {
        managerGroup5 := Buffer.toArray(managerBuffer);
      };
      case 5 {
        managerGroup6 := Buffer.toArray(managerBuffer);
      };
      case 6 {
        managerGroup7 := Buffer.toArray(managerBuffer);
      };
      case 7 {
        managerGroup8 := Buffer.toArray(managerBuffer);
      };
      case 8 {
        managerGroup9 := Buffer.toArray(managerBuffer);
      };
      case 9 {
        managerGroup10 := Buffer.toArray(managerBuffer);
      };
      case 10 {
        managerGroup11 := Buffer.toArray(managerBuffer);
      };
      case 11 {
        managerGroup12 := Buffer.toArray(managerBuffer);
      };
      case _ {

      };
    };

```

will see how it goes

---

<div class="post-metadata">

**Author:** ![skilesare](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/skilesare/32/5609_2.png) [@skilesare](https://forum.dfinity.org/u/skilesare)\
**Post date:** [August 20, 2024, 6:48pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/16 "2024-08-20T18:48:25Z")

</div>

> [@jamesbeadle](#):
>
> So the logging is the issue? or is it any await call to a different canister?

If you don’t await it is likely you’ll run out of cycles…I don’t think that is the issue.

---

<div class="post-metadata">

**Author:** ![jamesbeadle](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/jamesbeadle/32/10110_2.png) [@jamesbeadle](https://forum.dfinity.org/u/jamesbeadle)\
**Post date:** [August 20, 2024, 6:55pm UTC](https://forum.dfinity.org/t/motoko-function-doesnt-complete/34334/17 "2024-08-20T18:55:07Z")

</div>

Hey,

So I found the issue, bad code. I was transferring the managers between functions and I should just have done it in the function. Refactored and all working.

 ![image](https://us1.discourse-cdn.com/flex023/uploads/dfn/original/3X/a/b/ab394c6b6d103cb258cf0b2a381af945680962a0.jpeg)
