Reducing usage of resources with Zammad Chat Lazy instantiation

Hi,
For you without the patience to read everything - we implemented a button to open a Zammad chat when an attendant is available, otherwise opens a Zammad form, downloading and calling the javascript only if the user clicks in the button requesting for help reducing processing resources usage from 100% to 0.3% in average.

Motivation - Jump to Prototype if you don’t care.

We are using Zammad to replace our old helpdesk system.
Our target application (main app) is running in a cloud server, but Zammad is running out of it in a self deployed server with a processor of 4 cores and 16GB of RAM. Considering our infrastructure, we inserted Zammad chat in our target application with access to our little server. Since our target application receives about 10.000 access per hour without any surprises Zammad occupied 100% of the processing resources staling the server. Since we could not migrate Zammad to our cloud system, we had to find a solution ourselves.
By evaluating the Zammad chat plugin behavior, we noticed that at each access, despite the access being a common access or a legit helpdesk chat request, the javascript from Zammad was downloaded from our local server and stablished connection with the websocket. This behaviour is impossible to be sustained by our current infrastructure configuration, therefore, we had the idea to make the Zammad chat to become lazily instantiated, i.e., to be downloaded and instantiated if only and only if the user clicks in the button to start a helpdesk request. With our change, we reduced the usage of resources from 100% to 0.3%.

Prototype:

HTML/CSS objects required
——> We will use three buttons overlapped to instantiate and to access the Chat and the offline Form of Zammad.<——

**The presentation of the Zammad Button implementation below can be greatly improved by employing bootstrap classes and API.

<div style="margin:auto">
	<!-- Zammad form button - z-index must be the lowest among the three buttons - this button will be used to trigger the Zammad form when there are no attendants available to chat-->
	<button class="off-zammad-chat btn btn-danger" id="feedback-form" style="z-index: 498; position:fixed; right: 5px; bottom: 5px; float:right; width:30px; height:30px; text-align:center; vertical-align:middle; border-radius:15px; padding: 6px 0; font-size: 12px; line-height: 1.43;">?</button>

	<!-- Zammad chat button - z-index must be in the middle among the three buttons - this button will be used to trigger the Zammad chat when there are attendants available to chat trough the usage of reserved class "open-zammad-chat"-->
	<button class="btn open-zammad-chat btn-success" id="button-zammad" style="z-index: 499; position:fixed; right: 5px; bottom: 5px; float:right; width:30px; height:30px; text-align:center; vertical-align:middle; border-radius:15px; padding: 6px 0; font-size: 12px; line-height: 1.43;">?</button>

	<!-- Zammad lazy instatiation button - z-index must be the highest among the three buttons - this button will be used to trigger the Zammad lazy instantiation to load all libraries and scripts required to turn on the zammad chat-->
	<button class="btn btn-info" id="first-contact" style="z-index: 500; position:fixed; right: 5px; bottom: 5px; float:right; width:30px; height:30px; text-align:center; vertical-align:middle; border-radius:15px; padding: 6px 0; font-size: 12px; line-height: 1.43;">?</button>
	
</div>

The code below is responsible for the lazy instantiation of Zammad.


<!-- Javascripts come here - DO NOT CHANGE THE ORDER -->

<!-- Zammad typical requirements for operating the chat and the form -->
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script id="zammad_form_script"></script><!-- Without this line, the form does not work - notice that this is slightely different from what zammad uses, since we are not downloading the library for the form usage-->

<!-- All the magic comes below -->
<script>
	var YOUR_SERVER_IP="YOUR SERVER IP COMES HERE";
	var YOUR_SERVER_ZAMMAD_CHATJS= "https://".concat(YOUR_SERVER_IP).concat("/assets/chat/chat.min.js");
	var YOUR_SERVER_ZAMMAD_FORMJS= "https://".concat(YOUR_SERVER_IP).concat("/assets/form/form.js");
	var YOUR_SERVER_ZAMMAD_WebSocketSecure= "wss://".concat(YOUR_SERVER_IP).concat("/ws");

	// Sleep function to allow ZammadChat to be instatiated properly
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    // Loading Zammad Chat lazily 
    function load_ZammadChat(){
        //When called let us use an ajax call to download the js library required to implement Zammad
        return $.ajax({
            url: YOUR_SERVER_ZAMMAD_CHATJS,
            dataType: "script",
            success: function (){
            	//In case the library is downloaded and instantiated with success
            	//let us instantiate the ZammadChat object
                new ZammadChat({
                    fontSize: '12px',
                    chatId: 3,
                    host: YOUR_SERVER_ZAMMAD_WebSocketSecure, //This is super important, Zammad is unable to find the origin server IP when downloaded using AJAX - You must instantiate the host 
                    show: false // Since we are using a button, let us not open a chat randonly down the website
                });
                //This is where some magic is required
                //We use async to wait until the zammad chat object operate normally and in case there are no attendant available - it will hide the button with the class open-zammad-chat
                async function syncZChat() {
                    //Lets wait 1 sec
                    await sleep(1000);
                    //In case the button ZammadChat is hidden, we must call the form for offline attendance
                    if($("#button-zammad").hasClass('is-inactive')){
                    	//Case the Zammad form button is hidden, let us show it
                        $("#feedback-form").show();
                        //Automaticaly triggering the ZammadForm - this way the user does not have to click twice in the button
                        $("#feedback-form").trigger("click");
                        //Case the Zammad chat button is not hidden, let's hide it
                        $("#button-zammad").hide();
                    }else{
                    	//In case there are available attendants - let's open the chat for support
                        $("#button-zammad").trigger("click");
                    }
                }
                //Calling the syncZChat function created above
                syncZChat();
            }
        });
    };
    function load_ZammadForm(){
        return $.ajax({
            url: YOUR_SERVER_ZAMMAD_FORMJS,//Let's download the form library to use for offline support
            dataType: "script",
            success: function (){
            	//This looks redundant, but Zammad form requires that the div with the id zammad_form_script to have the url for the script to find the server and etc
                $('#zammad_form_script').attr({src: YOUR_SERVER_ZAMMAD_FORMJS});
                //In case the script is successfuly downloaded and instatiated, let us implement the Zammad form in the button with the feedback-form id
                $('#feedback-form').ZammadForm({
                    messageTitle: 'Contato', //Customize these fields as you like - I am using portuguese messages for customization
                    messageSubmit: 'Enviar',
                    messageThankYou: 'Obrigado pela pergunta (#%s)! N&oacute;s responderemos assim que poss&iacute;vel!',
                    showTitle: true,
                    modal: true 
                });
            }
        });
    };
    //Let's start the magic - When the user request for help by clicking in the button for the first time - we must download and implement all libraries and instantiate the ZammadChat and Form objects
    $("#first-contact").click(function (){
    	//Since the button was clicked already clicked - lets prevent reinstatiate everything every time by hiding the button
        $("#first-contact").hide();
        //Let us load all libraries for the chat and form
        load_ZammadChat();
        load_ZammadForm();
    });
</script>

I hope the code above can assist you reducing the usage of Zammad considering restrained computers regarding CPU resources.

Known Drawback - Users cannot change the page in use keeping the attendance across different pages.

Future implementation encompasses auto instantiation across multiple pages to avoid breaking attendance.

*I would like to thank Moises Silva for all the contributions developing this source code.

Cheers,
M. Marotta

1 Like