Wednesday, December 11, 2013

User might experince delay when join Lync Online Meeting.

Recently I’ve worked with large enterprise customer on troubleshooting strange issue with Lync Meeting join. Users from the pilot (50 people) group would report prolonged (up to 30 seconds) delay between the splash screen and the actual Lync Meeting join. A pattern was not observed (although there is one, just not obvious at first) – it would happen to random users, at random time, joining different meeting ID’s on different pools.

In this article I will explain the background of the “issue” and describe possible solution.

When user click Lync meeting link in format https://meet.contoso.com/user/M33T1NG1D , the request is processed by Director Pool member (if Simple URL points to Director), where after Meeting Discovery, Director Web Service will respond with “301 Moved permanently” to the original request. Client then sends new GET request with destination Web Service of the pool where the meeting will be hosted and meeting join completes.

As Lync server is installed on Windows Server, HTTP requests are served by Internet Information Services (IIS). The web sites (Internal or External) and Virtual Directories within the sites are driven by IIS Worker Process and are logically defined within IIS Application Pools.



As we see, not only whole Web sites (Internal or External), but also Virtual Directory within a web site might be configured to run under dedicated Application Pool.

One aspect of IIS Application Pool is “Recycling”. This process is defined in TechNet as “Internet Information Services (IIS) application pools can be periodically recycled to avoid unstable states that can lead to application crashes, hangs, or memory leaks.” When we install Lync server components, a default value is configured - 1740 minutes (29 hours).




When the Application Pool recycles, all items in the memory are released, a new w3wp process is created, configuration read and applied, .NET reloaded and we site is back serving requests. Under normal circumstances, had we had a request for simple web page as https://dialin.contoso.com , user would not experience visible delay because there is no complexity in assembling and serving this page.

However, Meeting Join request requires extensive server side processing, not discussed in this article. In reality, it takes about 22 seconds for the very first meeting join request to be served after Application Pool Recycle. This fact might cause inconvenience under certain circumstances – in my case a very large front end pool (nine pool members) and only 50 pilot users on this pool. Because the pool web services are Hardware Load Balanced, there is great chance that unique user would hit pool member where the Application Pool was just recycled and expertise 22+ seconds delay. Reports of type “It took forever to join the meeting this morning” were pouring in and frustration was growing fast.

The solution to eliminate the delay is rather simple – monitor the System Event Log for EventID 5074, examine the event description for which Application Pool was just recycled, and fire up Scheduled Task to execute PS script which will simulate real meeting join request. The request will perform “Application Pool warm-up” and because we do so immediately after recycle even, chances a real life user to attempt to join after Pool Recycling, but prior to Scheduled Task execution is practically non-existent.



Steps to configure Application Pool meeting join warm-up:
  

Step 1: Create folder “Scripts” on C:\
  • Inside this folder, create text file MeetExtWarUp.txt
  • The file should contain single line Invoke-WebRequest https://FE_Server_FQDN:4443/Meet?key=A1B2C3D4 where FE_Server_FQDN is the FQDN of your SE or EE Lync front end server.
  • Rename the file to MeetExtWarUp.ps1
  • Follow the steps above to create second .ps1 file where the text is 
    Invoke-WebRequest https://FE_Server_FQDN/Meet?key=A1B2C3D4
***Note that we use “:4443” for the External Web Site. It will be omitted in the file used for the Internal Web Site.


Step 2: Create Scheduled Task to execute the .ps1 script when AppPool recycle event is detected.

  • Start Task Manager as Administrator
  • Expand Microsoft/Windows node, right click and select "Create Task"



  • Name the task (WarmInternalAppPool in this example)
  • Check "Run with highest privileges"
  • Click "Change User or Group" button and select SYSTEM, then click OK.




  • Select "Triggers" tab.
  • Click "New"
  • In the "New Trigger" window, select "On an event" from "Begin the task:"
  • Toggle "Custom" under Settings
  • Click "New Event Filter" button



  • In New Event Filter window, click XML tab.
  • Check "Edit Query manually" check box
  • paste the following Query, where pay attention on the string describing which AppPool we want to use as trigger. For the Internal Web Site, we use LyncIntFeature and for External - LyncExtFeature.

<QueryList> <Query Id="0" Path="System"> <Select Path="System"> *[System[Provider[@Name='Microsoft-Windows-WAS'] and (EventID=5074)]] and *[EventData[Data[@Name='AppPoolID'] and (Data='LyncIntFeature')]] </Select> </Query> </QueryList>

  • Click OK on this window.
  • Click "Action" tab.
  • Click "New"
  • Type powershell.exe in "Program/script" box.
  • Add the following in "Add adgument (Optional):" box -ExecutionPolicy Unrestricted c:\Scripts\MeetExtWarmUp.ps1 where MeetXXXWarmUp.ps1 is the the name of the script we prepared earlier for the appropriate AppPool.



Complete the setup. your final configuration will look similar to mine.


What we just configured:

  1. Monitor the System Event Log for EventID 5074 (indicating AppPool recycle event"
  2. Examine the event to determine which AppPool was just now recycled
  3. Fire up the appropriate PowerShell script to sent fake meeting join request, thus forcing the server perform Meeting Join procedure (the server is not aware this is not a real meeting ID)

Step 3: Verify if our scheduled task works as expected.

Upon scheduled AppPool recycle, we find the corresponding entries as shown


Also, when examine the IIS log, we expect to see appropriate entries, indicating the meeting join request was invoked and precessed.


In conclusion, it is possible to "warm-up" the app pool of Lync Server Web Site to avoid meeting join delay.

This article can also be used as reference as of how to capture and evaluate specific event and execute Scheduled Task based on the input.

1 comment:

Mark Poulton said...

Thanks for the post. I took your idea and made a more generic script. Should work. Basically I wanted a batch file I could run that would automagically generate the FQDN since I tend to deploy large pools.

@echo off

REM
REM Determing the domain the compmuter is in
REM

FOR /F "tokens=1* delims=REG_SZ " %%A IN ('REG QUERY HKLM\System\CurrentControlSet\Services\Tcpip\Parameters /v Domain') DO (SET CURR_DOMAIN=%%B)

REM
REM Converting domain to upper case curr_domain
REM

IF [%curr_domain%]==[] goto huh
SET curr_domain=%curr_domain:a=A%
SET curr_domain=%curr_domain:b=B%
SET curr_domain=%curr_domain:c=C%
SET curr_domain=%curr_domain:d=D%
SET curr_domain=%curr_domain:e=E%
SET curr_domain=%curr_domain:f=F%
SET curr_domain=%curr_domain:g=G%
SET curr_domain=%curr_domain:h=H%
SET curr_domain=%curr_domain:i=I%
SET curr_domain=%curr_domain:j=J%
SET curr_domain=%curr_domain:k=K%
SET curr_domain=%curr_domain:l=L%
SET curr_domain=%curr_domain:m=M%
SET curr_domain=%curr_domain:n=N%
SET curr_domain=%curr_domain:o=O%
SET curr_domain=%curr_domain:p=P%
SET curr_domain=%curr_domain:q=Q%
SET curr_domain=%curr_domain:r=R%
SET curr_domain=%curr_domain:s=S%
SET curr_domain=%curr_domain:t=T%
SET curr_domain=%curr_domain:u=U%
SET curr_domain=%curr_domain:v=V%
SET curr_domain=%curr_domain:w=W%
SET curr_domain=%curr_domain:x=X%
SET curr_domain=%curr_domain:y=Y%
SET curr_domain=%curr_domain:z=Z%


echo.
echo Computer Name: %computername%
echo.
echo Current Domain: %curr_domain%
echo.
echo.

choice /t 1 /n /d y


PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Invoke-WebRequest https://%computername%.%curr_domain%:4443/Meet?key=A1B2C3D4}"

rem PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Invoke-WebRequest https://%computername%.%curr_domain%:443/Meet?key=A1B2C3D4}"


rem choice /t 60 /n /d y