Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Feedback Best way to ensure server side analytics sync before shutdown?

Discussion in 'Unity Analytics' started by TheLastVertex, Mar 25, 2021.

  1. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    I would like to add some analytic events to the server portion of a multiplayer game. The idea is to sync match data like class/hero type played, kills, deaths etc.

    These are dedicated servers running on AWS that have an average match length/lifespan of 3-5 minutes. At the end of the match, this match data is currently synced to a cloud database. Once that request is completed all players are disconnected and the server is terminated.

    Ideally I'd like to send this same data to unity analytics. From my understanding analytics will cache data if it can't send it immediately but is there anyway to verify or wait for the send instead? I need to make sure this data is fully synced before I shutdown the server.

    Also there is a large amount of data to send, about 30+ parameters worth. Apparently a single event shouldn't be more than 10 parameters. What's the best way to handle this? Send multiple 10 parameter events or each stat as a single event?
     
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    So you plan to send the data all at once at the end of a match? That's certainly possible. The method you'll want to use is Analyics.FlushEvents() https://docs.unity3d.com/ScriptReference/Analytics.Analytics.FlushEvents.html Keep in mind that you really only want to send those parameters that are expected to change each time. Some studios use a Parent/Child event structure and send the static information in a header event and use a GUID to link to child events with the parameters that expected to change. Also, you will likely find the Analytics dashboard too restrictive for your needs, and will require Raw Data Export, a Pro-only license feature https://docs.unity3d.com/Manual/UnityAnalyticsRawDataExport.html
     
  3. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    It would be ideal. The data is already gathered up at the end of the match at a single point so it would be easiest for me to just grab that same json data and pass it to unity analytics. There is some stats like hero/class played that could be sent at the start but the majority would have to wait for end of match since they are cumulative (kills, deaths, match length, time spent alive etc). It's ok if I have to send each stat one by one at the end of the match. I'm more worried that the sending gets cut off because the server gets terminated.


    Is there a callback or return value of some sort on this I can check if it was successful? When syncing to the cloud database I just wait for http request to complete before I initiate the server shutdown process. Is there something similar I could use for unity analytics? I just need a way to make sure it's successfully sent before I terminate.

    This is interesting, I'm new to the analytics game so if there is some information I should look at let me know (even just google search terms).

    Thank you.
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    No, there is no callback. There is no requirement or definition for a parent/child relationship, it was meant as a general design pattern. If you are sending flat events all at once, there is no need. Typically developers would send a header/parent event at level start, then progress events during the level using a GUID for correlation.
     
  5. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    Ahhh, ok. Thanks for the info.
     
  6. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    I should add that Analytics.CustomEvent() does have a callback of type AnalyticsResult

    AnalyticsResult ar = Analytics.CustomEvent("MyEvent");
    Debug.Log("Result = " + ar.ToString());

    should show the following for a successful call.

    Result = OK
     
  7. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    Thanks! I'll give this a shot. I think I can pair it down a bit for now and see how it goes.

    Is there any port requirements for analytics? The server manually opens a TCP and UDP port for player connections. Will it find these or is there potential for analytics to be blocked due to lack of port access?
     
  8. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    We use HTTPS and you'll need access to config.uca.cloud.unity3d.com and cdp.cloud.unity3d.com
     
  9. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    I was finally able to get around to test the server side analytics and they don't appear to be populating after 24hrs so I'm leaning towards something being wrong. Hopefully it's my code. I already use HTTP requests to execute other remote code so I'm assuming these are not being blocked. The code for the IEnumerator I'm using.

    Code (CSharp):
    1. //List for all analytic events to verify OK before shutdown
    2. List<AnalyticsResult> results = new List<AnalyticsResult>();
    3. bool complete = false;
    4. float timeout = 60;
    5.  
    6. //Add match played event
    7. results.Add(Analytics.CustomEvent("matchPlayed"));
    8.  
    9. //Flush the analytics data
    10. Analytics.FlushEvents();
    11. Debug.Log("Match Results Analytics: Flush started.");
    12.  
    13. //Wait for events to return OK
    14. while(complete == false && timeout > 0)
    15. {
    16.     int resultsCompleted = 0;
    17.     timeout -= Time.deltaTime;
    18.  
    19.     foreach (AnalyticsResult result in results)
    20.     {
    21.         if(result == AnalyticsResult.Ok)
    22.         {
    23.             resultsCompleted += 1;
    24.         }
    25.     }
    26.  
    27.     Debug.Log("Match Results Analytics: Waiting to complete: " + resultsCompleted + " of: " + results.Count);
    28.  
    29.     if(resultsCompleted == results.Count)
    30.     {
    31.         complete = true;
    32.         Debug.Log("Match Results Analytics: Completed!");
    33.     }
    34.  
    35.     yield return null;
    36. }
    37.  
    38. Debug.Log("Match Results Analytics: Exited.");
    I didn't include all the events I'm adding to that list but should give an idea of what I'm doing. The server logs report the following:

    Match Results Analytics: Flush started.
    Match Results Analytics: Waiting to complete: 6 of: 6
    Match Results Analytics: Completed!
    Match Results Analytics: Exited.

    Those log entries show all the events I'm sending / verifying are actually returning OK. Good but... It is surprising that that the first loop is showing "6 of 6" complete. That is the exact order of the logs which seems odd that they would all be complete on the first loop? I would assume this would take at least some time for the requests and the log would show a few "Waiting to complete: 1 of 6", "2 of 6" etc to be made but it appears to be returning OK for all events immediately.

    Is there a faster way to verify this is working that doesn't' require me to wait 24hrs for the analytics dashboard to populate?
     
  10. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    No there isn't any "faster" way. You can use Charles Proxy to determine if the events are being sent. There is no guaranteed order of events, we do local caching then send in batches. I'm not clear what you are attempting to do in that code. You simply need to call Analytics.CustomEvent(..) followed immediately by FlushEvents(), it seems you are over complicating it. Sometimes it takes longer than 24 hours. But use Charles Proxy to confirm. You'll need to run it on the server in your case. You'll need to reboot it to install the Root certificate. https://support.unity.com/hc/en-us/articles/115002917683-Using-Charles-Proxy-with-Unity If you continue to have issues, I might suggest to simplify the problem, and create a new MyAnalyticsTest project that only sends a single event. See if a simple case can send events as you are suggesting from your server. Typically Analytics is meant to run on the client device.
     
  11. TheLastVertex

    TheLastVertex

    Joined:
    Sep 30, 2015
    Posts:
    126
    I'll try something simpler today with a single event and see what I find out. Thanks for the link to Charles Proxy I'll give it a look, the biggest issue is just not being able to iterate quickly on this to troubleshoot.

    I'm sending match results to unity analytics at the end of a game just before the game server shuts down. I send/queue up all the requests then wait until each one has returned OK so I know it is safe to shutdown the server process.

    I'm attempting to treat it like a http request. I'm sending a Google Firebase Function request just before this that waits and verifies https return status = 200 before the shutdown as well. Ideally I'd want the same logic. This way the server only waits the needed amount of time, and shutdown only starts after it has been confirmed all events have been handled.

    If I just call FlushEvents() and don't have a way to wait, the server process will be terminated in the next line. I'm assuming this will not be enough time for the requests to be processed. I can add an artificial timer to just wait 1-5 minutes etc (Which I'll probably do to test this), but I would really like a way to process this like a normal http request.

    Is there a way to skip the Analytics.CustomEvent() method and just send a raw http request to unity analytics manually?

    I understand for client devices their is lots of behind the scenes stuff for caching and processing next time the user starts the app. But for server side, once I kill that process it's gone. These servers are being started, stopped, and spun up dynamically by AWS and I'm getting billed by the millisecond. I'd prefer not to have a server process hanging around on the hope that the events got sent in time.
     
  12. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    @TheLastVertex No there isn't such a way send an http request. Unity Analytics might not be the best solution for you. You might want to send the events to your own HTTP server where you have full control over everything.