question

robert avatar image
robert asked

UnlockContainterItem and CloudScriptExecutionTimeLimitExceeded

For our upcoming game we have special items - which when purchased - will add quite a few items to the users inventory.

We have a little problem with one of this items: For example, Special Pack, contains 10 items with 25 balls. So the container item Special Back has 10 bundled items with a amount of 25 set for each item.

Sometimes we get a CloudScriptExecutionTimeLimitExceeded when calling UnlockContainerItem, it this a known issue? And if so, how can we workaround this, or is there a better best practice for this?

The balls itself are set as stack items so that at a maximum of 10 items should be added to the users inventory (with a usage count of 25 set then)

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Can you please provide the specifics of the Item IDs you're attempting to add, and the Title ID of the game, so that we can have a look? It is indeed the case that attempting to add a large number of items can cause delays to completion of the process - and so, trying to do so in Cloud Script can cause timeouts. But I would not expect that for an addition of 10-25 items. If you mean that each of the 10 items adds 25 items, making it actually 250, then yes, that absolutely would cause timeouts. But we can have a look at the specifics and get you some feedback.

21 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

heikohufnagl avatar image heikohufnagl commented ·

Hi Brendan, the title ID is 9168 and we're trying to unlock 25xBallAllrounder, 25xBallBouncer, 25xBallCurver, 25xBallDominator, 25xBallLowFlyer, 25xBallPutter, 25xBallRanger, 25xBallSticker and 25xBallWindbreaker with on UnlockContainerItem call. Thank you for help.

0 Likes 0 ·
robert avatar image robert heikohufnagl commented ·

The container item we try to unlock with all this balls bundled is OfferExclusiveBallSet.

We assumed that using the quality field with 25 items would just internally add the item once and just set the usage count to 25 because of the stacked property. On a side note: We also return the result of the UnlockContainerItem to the client to display a nice "You unlocked stuff" reward showing all the unlocked bundled items with their count.

0 Likes 0 ·
brendan avatar image brendan robert commented ·

So, the way it works is that we first create the package of all the items to be added. Then, we aggregate items that are stackable into a single stack each. Then finally, we add the items to the player inventory. So basically, yes, each stackable item is only - roughly speaking - as costly as adding a single item, in terms of CPU/database time. But adding that many items all at once will require a noticeable amount of time which will vary based upon the size of the player inventory. Ultimately, if this is being called from ExecuteCloudScript, it shouldn't be an issue. But if you're trying to do this from a PlayStream Action, that's likely to run into issues. Bear in mind that PlayStream Actions can occur at a much higher rate, and so they're limited to a relatively small amount of total processing time. If this is something you're trying to do on player_added_title, it might be better to move it to an ExecuteCloudScript call from the client on the first gameplay experience.

0 Likes 0 ·
Show more comments
robert avatar image robert commented ·

Thanks for the insights Brendan. You may look at player 21F34334516F6571 from the title 9168. This player has 36 active items but more than 4000 expired items (this is from manual testing mostly).

Will expired items also influence the time required to grant new items?

0 Likes 0 ·
brendan avatar image brendan robert commented ·

They do until they're archived. That's actually a common issue with titles doing intensive testing that doesn't reflect real player behavior - purchasing an item hundreds of times in a row, or granting items in ways that aren't actually possible in real gameplay. So it's possible that's the cause, but we'll have a look at that account.

0 Likes 0 ·
heikohufnagl avatar image heikohufnagl brendan commented ·

Hi Brandon, could you reproduce the issue with the given account? We're still having the issue with various test accounts. Tomorrow we will release the game, but it looks like we have to cancel some functionality because of the problem.

0 Likes 0 ·
Show more comments
robert avatar image robert commented ·

Actually we call PurchasedOffer which calls UnlockContainterItems from the client via ExecuteCloudScript. Shouldn't the 5 seconds limit be enough for the kind of operations we perform? (according to the play stream event the method needs around 7.5 seconds to complete to grant 10 items)

0 Likes 0 ·
brendan avatar image brendan robert commented ·

All the ones I saw in a quick review were Cloud Scripts triggered from Actions, but I do see one which was from a client-initiated call to ExecuteCloudScript. Short answer is, it depends on what you're trying to do. Reviewing that Cloud Script, it appears to be calling the following Server API methods (in order):

  • UnlockContainerItem
  • WritePlayerEvent (twice)
  • GetUserInternalData
  • UpdateUserInternalData
  • GetUserInventory
  • GetUserReadOnlyData

For all use of Cloud Script, I highly recommend checking your total execution time and making sure that in your testing you're not getting close to 80% of your available execution time, to be safe. Given that every Server API call is a Web API call (all of PlayFab cannot run on a single server), each is going to take some non-trivial amount of time, though the latency should be fairly small.

0 Likes 0 ·
robert avatar image robert commented ·

Thanks. We are very well aware of the execution time required and optimize them as much as possible.

But this method is very special. It takes about 0.4 seconds to execute if we don't unlock the container but takes more than 7 second if we use UnlockContainterItems. It appears that UnlockContainterItems works fine if we unlock just up to 10 items with a count of 1 for each item. As soon as we set the count to 25 (items are stacked) the function times out. Is there any information about the required time for UnlockContainterItem depending on the bundled items? Its almost impossible to predict how much time the function requires so for now its a trial and error. And with the time limit we are not able to offer nice packages to the user if we can't unlock the balls for example.

0 Likes 0 ·
brendan avatar image brendan robert commented ·

Hm. The time to grant N of a single stackable should be only barely more than the time to add 1 of that stackable, but let me have another look at the container code path. It's possible that it hasn't been optimized yet. If not, your best bet would be to add only one of each, and then adjust the usage count of the items (any calls that operate on an item instance ID will always be as fast as possible, since items are indexed on that).

0 Likes 0 ·
brendan avatar image brendan robert commented ·

Ah - wait! You're using UnlockContainerItem. Please switch that to UnlockContainerInstance. That's the optimized code path.

0 Likes 0 ·
heikohufnagl avatar image heikohufnagl brendan commented ·

Hi Brendan,

thank you for the hint with UnlockContainerInstance, I tried to use it but I'm having functional issues with it. I try to unlock this container "OfferStarterPack":

It did not work using cloud script and I get the same error with Try It:

The result indicates missing container item, but an item with the given instanceID is in the players inventory. Do you have any idea? Thank you!

0 Likes 0 ·
Show more comments
Show more comments
robert avatar image
robert answered

We now tried the UnlockContainterItemInstance with one of our "big" packs which unlocks 10 stacked items.

This is the result we get from the try it method:

Title ID

D82C

ContainerItemInstanceId: (Required)

985D0BABAFF711F

KeyItemInstanceId: (Optional)

9C09622035051D78

PlayFabId: (Required)

6089D000CE291297

API Call Results

{

"code": 200,

"status": "OK",

"data": {

"UnlockedItemInstanceId": "985D0BABAFF711F",

"UnlockedWithItemInstanceId": "9C09622035051D78",

"GrantedItems": [

{

"ItemId": "BallPutter",

"ItemInstanceId": "7603C781AAA065CF",

"PurchaseDate": "2017-11-16T05:57:27.699Z",

"RemainingUses": 73,

"UsesIncrementedBy": 25,

"CatalogVersion": "1.0",

"BundleParent": "E8A103DC4FD736C6",

"UnitPrice": 0

},

{

"ItemId": "BallSticker",

"ItemInstanceId": "854C02D0C742AD43",

"PurchaseDate": "2017-11-10T18:31:02.85Z",

"RemainingUses": 140,

"UsesIncrementedBy": 25,

"CatalogVersion": "1.0",

"UnitPrice": 0

},

{

"ItemId": "BallAllrounder",

"ItemInstanceId": "E3DB815C31E65C4C",

"PurchaseDate": "2017-11-16T05:57:27.699Z",

"RemainingUses": 72,

"UsesIncrementedBy": 25,

"CatalogVersion": "1.0",

"BundleParent": "E8A103DC4FD736C6",

"UnitPrice": 0

},

{

"ItemId": "BallBouncer",

"ItemInstanceId": "35558A5C137AEC0B",

"PurchaseDate": "2017-11-13T09:08:39.794Z",

"RemainingUses": 78,

"UsesIncrementedBy": 25,

"CatalogVersion": "1.0",

"UnitPrice": 0

},

{

"ItemId": "BallCurver",

"ItemInstanceId": "F022B2109062BAE9",

"PurchaseDate": "2017-11-16T05:57:27.699Z",

"RemainingUses": 72,

"UsesIncrementedBy": 25,

"CatalogVersion": "1.0",

"BundleParent": "E8A103DC4FD736C6",

"UnitPrice": 0

},

{

"ItemId": "BallDominator",

"ItemInstanceId": "43B9814E103EB8C7",

"PurchaseDate": "2017-11-16T05:57:27.699Z",

"RemainingUses": 72,

"UsesIncrementedBy": 25,

"CatalogVersion": "1.0",

"BundleParent": "E8A103DC4FD736C6",

"UnitPrice": 0

},

{

"ItemId": "BallRanger",

"ItemInstanceId": "E4EF2DE9C251B3FD",

"PurchaseDate": "2017-11-13T08:22:19.022Z",

"RemainingUses": 159,

"UsesIncrementedBy": 25,

"Annotation": "Unlocked Crate",

"CatalogVersion": "1.0",

"UnitPrice": 0

},

{

"ItemId": "BallWindBreaker",

"ItemInstanceId": "6CC03D7752A16A86",

"PurchaseDate": "2017-11-13T08:22:19.366Z",

"RemainingUses": 134,

"UsesIncrementedBy": 25,

"Annotation": "Unlocked Crate",

"CatalogVersion": "1.0",

"UnitPrice": 0

},

{

"ItemId": "BallLowFlyer",

"ItemInstanceId": "3168571E1E70EA3B",

"PurchaseDate": "2017-11-16T05:57:27.699Z",

"RemainingUses": 75,

"UsesIncrementedBy": 25,

"CatalogVersion": "1.0",

"BundleParent": "E8A103DC4FD736C6",

"UnitPrice": 0

}

]

},

"CallBackTimeMS": 14095

}

Looks like it took 14seconds to perform this call. Is it really intended that adding 10 items takes this long in our case?

3 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image brendan commented ·

Well first, it's not 10 items. It's 250 items - 25 each of 10 stackables. The amount of time required to add items to inventory depends on a number of factors. The total size of the player's current inventory is one, as is the total number of items being added. But one other is the status of the queue of items being revoked or stacked. So if you use a single account for testing and keep adding items that are stackables to it in a short period, the grant time is going to increase for that account, as the revoke/stack queue is still being processed for that player account. Basically, we'd need a lot more information about the specifics of your test scenario to say for sure why the grant took longer than usual.

0 Likes 0 ·
robert avatar image robert commented ·

Well, we are a bit stuck here.

If it is 250 or 25 items is an implementation detail in my point of view. One could say we add just 10 items where internally the usage count is simply set to 25. Obviously this is not the case and playfab internally just adds 250 items and combines them maybe later. Not sure about that.

But for us this just means we cannot add only 10 items with a usage count of 25. It not only happens with our test account but with real user accounts too. All this ball items expire also for users (or will be consumed), so in this configuration with the method needing +10 seconds for just 10 ball items it will never work.

If we would add 250 items, item by item, we would accept that it takes too long, way too much items. But we intentionally designed our system in such a way that we just add 10 different items with the usage count set to the desired number. We never thought unlocking a container with 10 items included would take +10 seconds.

0 Likes 0 ·
brendan avatar image brendan robert commented ·

No, the stacking of items occurs before adding them to the player inventory - I'm simply saying that there are multiple factors, and while that's not going to be the majority of the time, we still have to consider it. All inventory operations are impacted by the number of items being added, the size of the current player inventory, and for cases that include stackables, the number of items awaiting cleanup from previous stacking operations. So rapidly adding a few items at a time can have nearly as much impact as adding them all in one call.

That's why I'm trying to get a repro that has the same characteristics as your test - normally, I would not expect the operation you describe to take that long, so I need to see the details of what occurred during your test. Unfortunately, the Title ID in question (D82C) has no containers in its Catalog right now, so I can't test directly. Also, the PlayFab ID you mentioned (6089D000CE291297) doesn't have any inventory operations in its history:

https://developer.playfab.com/en-us/D82C/players/6089D000CE291297/event-history

Can you re-check the details of your test?

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.