<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Property Finder Engineering and Tech Blog - Medium]]></title>
        <description><![CDATA[Creative and innovative engineers, data and product professionals working to motivate and inspire everyone to get living the life they deserve - Medium]]></description>
        <link>https://medium.com/propertyfinder-engineering?source=rss----18960d28ee42---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Property Finder Engineering and Tech Blog - Medium</title>
            <link>https://medium.com/propertyfinder-engineering?source=rss----18960d28ee42---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 05:23:39 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/propertyfinder-engineering" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[5 Essential AI Tools Every Tech Professional Should Master in 2025]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/propertyfinder-engineering/5-essential-ai-tools-every-tech-professional-should-master-in-2025-21ddf3408148?source=rss----18960d28ee42---4"><img src="https://cdn-images-1.medium.com/max/1280/1*lBBWp4V0WMqvv-ARdpA-lQ.png" width="1280"></a></p><p class="medium-feed-snippet">AI tools have become indispensable for developers and tech professionals seeking to stay competitive and efficient.</p><p class="medium-feed-link"><a href="https://medium.com/propertyfinder-engineering/5-essential-ai-tools-every-tech-professional-should-master-in-2025-21ddf3408148?source=rss----18960d28ee42---4">Continue reading on Property Finder Engineering and Tech Blog »</a></p></div>]]></description>
            <link>https://medium.com/propertyfinder-engineering/5-essential-ai-tools-every-tech-professional-should-master-in-2025-21ddf3408148?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/21ddf3408148</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Anshita Bhasin]]></dc:creator>
            <pubDate>Mon, 02 Jun 2025 13:28:24 GMT</pubDate>
            <atom:updated>2025-06-02T13:28:24.319Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Cypress || Must-Have Plugins & Libraries for Seamless Testing with Cypress]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/propertyfinder-engineering/cypress-must-have-plugins-libraries-for-seamless-testing-with-cypress-c4f6dc25e0aa?source=rss----18960d28ee42---4"><img src="https://cdn-images-1.medium.com/max/1280/1*3clqF4Lh6q9orhiNLp-76w.png" width="1280"></a></p><p class="medium-feed-snippet">Welcome to Part 1 of our series on Cypress&#x200A;&#x2014;&#x200A;Plugins &amp; Libraries. In this series, we&#x2019;ll explore essential plugins and libraries that&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/propertyfinder-engineering/cypress-must-have-plugins-libraries-for-seamless-testing-with-cypress-c4f6dc25e0aa?source=rss----18960d28ee42---4">Continue reading on Property Finder Engineering and Tech Blog »</a></p></div>]]></description>
            <link>https://medium.com/propertyfinder-engineering/cypress-must-have-plugins-libraries-for-seamless-testing-with-cypress-c4f6dc25e0aa?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/c4f6dc25e0aa</guid>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[cypress]]></category>
            <category><![CDATA[automation-testing]]></category>
            <category><![CDATA[testing]]></category>
            <dc:creator><![CDATA[Anshita Bhasin]]></dc:creator>
            <pubDate>Thu, 14 Mar 2024 06:27:38 GMT</pubDate>
            <atom:updated>2024-03-14T06:27:38.504Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Centrally Managing Jenkins Jobs With a Jenkins Template]]></title>
            <link>https://medium.com/propertyfinder-engineering/centrally-managing-jenkins-jobs-with-a-jenkins-template-fcf63e943458?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/fcf63e943458</guid>
            <category><![CDATA[groovy]]></category>
            <category><![CDATA[dsl]]></category>
            <category><![CDATA[template]]></category>
            <category><![CDATA[jenkins-pipeline]]></category>
            <category><![CDATA[jenkins]]></category>
            <dc:creator><![CDATA[Dinuka Jayamaha]]></dc:creator>
            <pubDate>Tue, 10 Oct 2023 10:47:50 GMT</pubDate>
            <atom:updated>2023-10-10T10:47:50.178Z</atom:updated>
            <content:encoded><![CDATA[<p>As a company’s infrastructure grows so does the amount of jobs which are running in their Jenkins servers. Most of the time these jobs are very similar to each other with minor differences. As these jobs keep growing, the number of DSL files used to maintain these jobs also grows and It becomes a hassle to maintain these jobs individually. Take for example a typical build job used to build a docker image. The DSL file and the shell script used to create the Jenkins job is given below:</p><pre>freeStyleJob(&#39;build-some-app-master-image&#39;) {<br>  description &#39;Build some-app docker images from master&#39;<br>  scm {<br>      git {<br>          remote {<br>              url(https://medium.com/&#39;git@github.com:acme/some_app.git&#39;)<br>              credentials(&#39;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx&#39;)<br>              branch(&#39;master&#39;)<br>          }<br>          triggers {<br>              githubPush()<br>          }<br>      }<br>  }<br>  steps {<br>    shell(readFileFromWorkspace(&#39;build_app_master_image.sh&#39;))<br>  }<br>}<br></pre><pre>#!/bin/bash<br>set -e<br><br>export AWS_DEFAULT_REGION=&quot;us-west-1&quot;<br>export DOCKER_IMAGE=&quot;some-app&quot;<br>export ECR_REPO=&quot;111111111111.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com&quot;<br><br>docker build -t ${ECR_REPO}/${DOCKER_IMAGE}:latest .<br>docker push ${ECR_REPO}/${DOCKER_IMAGE}:latest</pre><p>If the need arises to add an additional build step to this job, for example if there is a requirement to enable slack notifications for each build job failure, each DSL file for each application needs to be modified to support this change</p><p>A better way to create and maintain these files/jobs</p><p>The solution to this is to centrally maintain a single template which accepts parameters and creates multiple jobs according to the parameters this template receives.</p><p>Given below is the same build job that was shown above written in such a way to receive parameters so that it generates multiple build jobs.</p><p>An array is defined which contains the parameters for each application. This array is fed to a loop which traverses the array through a JSON parser.</p><p>When you run this DSL script on your Jenkins server it produces the build jobs that you defined in the array.</p><pre>import groovy.json.JsonSlurper<br><br>def slurper = new groovy.json.JsonSlurper()<br><br>def application_list = slurper.parseText(&#39;[{&quot;name&quot;:&quot;app_one&quot;,&quot;organisation&quot;:&quot;acme&quot;,&quot;app_repo&quot;:&quot;app_one&quot;,&quot;branch&quot;:master&quot;,&quot;aws_account&quot;:123456789123&quot;,&quot;aws_region&quot;:ap-southeast-1&quot;,&quot;image_name&quot;:app_one&quot;}, {&quot;name&quot;:&quot;app_two&quot;,&quot;organisation&quot;:&quot;acme&quot;,&quot;app_repo&quot;:&quot;app_two&quot;,&quot;branch&quot;:master&quot;,&quot;aws_account&quot;:123456789123&quot;,&quot;aws_region&quot;:ap-southeast-1&quot;,&quot;image_name&quot;:app_two&quot;}]&#39;)<br><br>application_list.eachWithIndex { application, index -&gt;<br>  freeStyleJob(&quot;build-master-image-${application.name}&quot;)<br>  {<br>    description &#39;Build ${application.name} docker image from master&#39;<br>    scm {<br>      git {<br>        remote {          <br>          url(https://medium.com/&#39;git@github.com:${application.organisation}/${application.app_repo}.git&#39;)<br>          credentials(&#39;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx&#39;)<br>          branch(&#39;${application.branch}&#39;)<br>        }<br>        triggers {<br>          githubPush()<br>        }<br>      }<br>    }<br>    environmentVariables {<br>      envs(<br>        AWSACCOUNTID: &quot;${application.aws_account}&quot;<br>        AWSDEFAULTREGION: &quot;${application.aws_region}&quot;<br>        DOCKERIMAGE: &quot;${application.image_name}&quot;<br>      )<br>    }<br>    steps {<br>      shell(readFileFromWorkspace(&#39;build_app_master_image.sh&#39;))<br>    }<br>  }<br>}</pre><pre>#!/bin/bash<br>set -e<br><br>export DOCKER_IMAGE=&quot;${DOCKERIMAGE}&quot;<br>export ECR_REPO=&quot;${AWSACCOUNTID}.dkr.ecr.${AWSDEFAULTREGION}.amazonaws.com&quot;<br><br>docker build -t ${ECR_REPO}/${DOCKER_IMAGE}:latest .<br>docker push ${ECR_REPO}/${DOCKER_IMAGE}:latest</pre><p>This approach gives you a base to build increasingly complex templates by using the various capabilities and characteristics of the groovy language. To make it even more interesting this template can be configured to get the application configuration list from a remote api. In an environment which follows DevOps practices a pipeline can be created to automatically trigger the jobdsl build job when the application api is updated.</p><pre>import groovy.json.JsonSlurper<br><br>def application_list = new JsonSlurper().parseText( new URL(&quot;https://application_list.acme.com/list&quot;).getText() )<br><br>application_list.eachWithIndex { application, index -&gt;<br> freeStyleJob(&quot;build-master-image-${application.name}&quot;)<br> {<br>   description &#39;Build ${application.name} docker image from master&#39;<br>   scm {<br>       git {<br>           remote {  <br>               url(https://medium.com/&#39;git@github.com:${application.organisation}/${application.app_repo}.git&#39;)<br>               credentials(&#39;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx&#39;)<br>               branch(&#39;${application.branch}&#39;)<br>           }<br>           triggers {<br>               githubPush()<br>           }<br>       }<br>   }<br>   environmentVariables {<br>     envs(<br>       AWSACCOUNTID: &quot;${application.aws_account}&quot;<br>       AWSDEFAULTREGION: &quot;${application.aws_region}&quot;<br>       DOCKERIMAGE: &quot;${application.image_name}&quot;<br>     )<br>   }<br>   steps {<br>     shell(readFileFromWorkspace(&#39;build_app_master_image.sh&#39;))<br>   }<br> }<br>}</pre><p>In conclusion, as a company’s infrastructure grows, managing an increasing number of similar Jenkins jobs can become a significant challenge. To streamline this process and maintain efficiency, the solution proposed involves creating and maintaining a single template capable of generating multiple jobs based on parameters. This approach not only simplifies job management but also opens the door to automation, allowing job creation to align seamlessly with changes in application configurations through a remote API, in line with DevOps practices.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fcf63e943458" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/centrally-managing-jenkins-jobs-with-a-jenkins-template-fcf63e943458">Centrally Managing Jenkins Jobs With a Jenkins Template</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Software Testing Ecosystem]]></title>
            <link>https://medium.com/propertyfinder-engineering/software-testing-ecosystem-f0c9b55dbdbc?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/f0c9b55dbdbc</guid>
            <category><![CDATA[automation-testing]]></category>
            <category><![CDATA[latest]]></category>
            <category><![CDATA[qa]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[software-testing]]></category>
            <dc:creator><![CDATA[Anshita Bhasin]]></dc:creator>
            <pubDate>Thu, 07 Sep 2023 04:15:28 GMT</pubDate>
            <atom:updated>2023-12-12T18:56:28.803Z</atom:updated>
            <content:encoded><![CDATA[<p>Sharing the Mind Map on the Software Testing Ecosystem, a one-stop platform to explore various tools! 🌐</p><p>Based on my industry knowledge and experience, I have created this mind map that covers a wide range of essential testing tools and platforms. It includes IDEs, Performance and Functional Testing Tools, Reporting Solutions, Container Platforms, Database Testing Tools, and more.</p><p>👉 No more hassle searching for testing tools! Each component comes with a clickable link, making navigation a breeze. Share this testing mindmap with your fellow testers 🤝</p><p>If you want to navigate to that tool page, just click on the click from that box as shown below</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Wy3ZRcxUqYPfAcouLFbTNg.png" /></figure><p>Link —<a href="https://xmind.app/m/YfjDUt">https://xmind.app/m/YfjDUt</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nsZNsL5gpdzj9qAujc6oLQ.png" /></figure><p>Thanks for reading. Happy learning — AB!</p><p>Thanks, <a href="https://medium.com/u/63406024ff34?source=post_page-----5df42888b7cf--------------------------------">Naveen AutomationLabs</a> for the guidance.</p><p><strong>Anshita Bhasin</strong><br>QA Chapter Lead</p><p><a href="https://github.com/Anshita-Bhasin">GitHub</a> | <a href="https://www.linkedin.com/in/anshita-bhasin/">LinkedIn</a> | <a href="https://twitter.com/anshita__bhasin">Twitter</a> | <a href="https://www.youtube.com/channel/UCtNHEcO_c9qpaUqIYSb98Rg">Youtube</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f0c9b55dbdbc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/software-testing-ecosystem-f0c9b55dbdbc">Software Testing Ecosystem</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cypress 13: Test Replay and Cypress Dashboard]]></title>
            <link>https://medium.com/propertyfinder-engineering/cypress-13-test-replay-and-cypress-dashboard-690a95139ed7?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/690a95139ed7</guid>
            <category><![CDATA[cypress]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[automation-testing]]></category>
            <category><![CDATA[property-finder]]></category>
            <dc:creator><![CDATA[Anshita Bhasin]]></dc:creator>
            <pubDate>Wed, 06 Sep 2023 15:14:25 GMT</pubDate>
            <atom:updated>2023-09-07T04:13:55.200Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y4xfd3gz6OS5LB0x2DdhTg.png" /></figure><p>Are you tired of spending countless hours debugging your tests? Look no further than Cypress version 13’s new feature: <strong>Test Replay.</strong> This game-changing addition, in conjunction with the Cypress Dashboard, will take your testing workflow to the next level.</p><p>In this blog post, we’ll explore what Test Replay is and how the Cypress Dashboard enhances your testing workflow.</p><h3>What is Cypress Dashboard?</h3><p>The Cypress Dashboard is a cloud platform that provides a comprehensive view of your test runs across different environments and browsers.</p><p>Below are some of the main features of Cypress Dashboard:</p><ul><li>It provides a centralized platform to view detailed test results, including screenshots and videos, to quickly identify and analyze test failures.</li><li>Using Cypress Dashboard, you can run your test cases in parallel across multiple virtual machines in CI and save a lot of time.</li><li>It helps you gain a comprehensive view of your test suite’s health and performance over time.</li><li>It helps you find the flaky test in your code based on their frequency, and severity.</li><li>It provides you with a quick summary of errors occurring in your test. You can easily read the exact error message and understand how many tests are impacted by each error.</li></ul><p>By default, It comes with <strong>3 users and 500 runs</strong> for the free version but if you want to leverage more test runs, you can always switch to its paid version ( Here’s the pricing, you can choose based on the requirements)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7lZ8oHpmZGmpGKQc0NAHTQ.png" /></figure><p>You can configure it for multiple projects and record your test cases on Cypress cloud (Dashboard) to view the screenshots, and videos and even configure to check the flaky test cases.</p><p>It shows, which git branch you are using for running test cases in case you are running on CI/CD, just like shown below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6rQkKqx367s43TgMEMb5tg.png" /></figure><p>In addition, you also have the ability to configure it to monitor the slowest test runs in your project, as well as Flake Tests, Test Runs, and durations.</p><p>Simply navigate to the configuration option in the left side menu and customize it according to your specific requirements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*WzHLZsG7Q7E7F3IxrcJ2lw.png" /></figure><p>It also offers exceptional integration capabilities. You can easily integrate it with various tools like Github, Gitlab, BitBucket, etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ggrX31T2dKXTwuY8N9MTRA.png" /></figure><p>Now that you have a clear understanding of what the Cypress Dashboard is, let’s move on to the next section and explore what Test Replay is.</p><h3>Introducing Test Replay</h3><p>Test Replay is a new game-changing feature introduced in Cypress version 13 that empowers you to conquer flaky and failing tests with ease during Continuous Integration (CI) runs.</p><ul><li>It allows you to re-run specific test cases or scenarios, providing valuable insights into what went wrong during the test execution on CI/CD.</li><li>With Test Replay, you can pinpoint issues, debug failures, and make your test suite more robust and reliable.</li><li>This feature simplifies the debugging process, making it faster and more efficient, saving you time and effort.</li></ul><p>The best part is that there is no additional cost to use this feature if you are already using Cypress Dashboard. Simply update your Cypress version to version <strong>13.0 </strong>in your<strong> </strong>package.json file, and you can start using Test Replay right away.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/488/1*VjXObBOoKUl-oPeOI_Nz4g.png" /></figure><p>Test Replay is compatible with all three types of testing, including <strong>E2E, API, and Component Testing</strong>. To access Test Replay, navigate to your project and then proceed to your test results.</p><p>Simply hover over any failed test cases, and you will notice the appearance of the Test Replay button, as illustrated below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lM4EvjEuxa6Gvg57Kd0Jfw.png" /></figure><p>Upon clicking on the Test Replay button, a new window will appear, displaying the test execution along with the following details:</p><blockquote>Operating System on which it is running</blockquote><blockquote>Browser Name</blockquote><blockquote>Test Case Name</blockquote><blockquote>Network Calls</blockquote><blockquote>Console</blockquote><blockquote>Inspect element</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Wlfnh3lgl5h5miA6TZwpMA.png" /></figure><p>You have the flexibility to adjust the speed of test execution, allowing for better debugging and viewing capabilities.</p><h3>Benefits of Test Replay:</h3><p>Test Replay is a powerful tool that enables automation engineers and developers to identify and debug issues in their test suite quickly and efficiently. By re-running specific test cases or scenarios, Test Replay provides valuable insights into what went wrong during the test execution on CI/CD.</p><p>Here are some of the key benefits of using Test Replay:</p><h4><strong>Collaboration</strong>:</h4><p>Test Replay makes it easier for team members to collaborate on debugging efforts. Since the test execution and results are captured, team members can easily share and discuss the details with each other.</p><h4>Faster Debugging:</h4><p>Test Replay reduces the time required for debugging by providing a detailed view of the test execution. This helps automation engineers/developers identify the root cause of the failure faster and take corrective action.</p><h4>Improved Test Coverage:</h4><p>By identifying and fixing flaky tests, Test Replay helps improve overall test coverage. This ensures that your application is thoroughly tested and reduces the risk of bugs in production.</p><h4>Customizable:</h4><p>Test Replay is customizable, allowing you to select which parts of the test execution you want to replay. This is particularly useful when dealing with long test cases or when you only need to replay a specific portion of the test.</p><p>If you would like to learn more about how to utilize this feature, you can watch the below video for a more comprehensive understanding.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FxpkKlcyAVrM%3Flist%3DPLUPlX-9QUIrOOwnzYkmU9YioOmkFSLmCe&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DxpkKlcyAVrM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FxpkKlcyAVrM%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/8c5a75d495d07c306d8b34d6634f510f/href">https://medium.com/media/8c5a75d495d07c306d8b34d6634f510f/href</a></iframe><h3>Conclusion:</h3><p>In conclusion, Cypress Dashboard is a powerful tool that can help you streamline your testing workflow and with the new <strong>TestReplay</strong> feature, you can easily debug failing tests. So, whether you’re running E2E, API, or Component Testing, Cypress Dashboard has got you covered</p><p>Thanks for reading. Happy Learning! AB</p><p>Ref — <a href="https://docs.cypress.io/guides/cloud/debugging/test-replay">https://docs.cypress.io/guides/cloud/debugging/test-replay</a></p><p><strong>Anshita Bhasin</strong><br>Sr. Automation Engineer</p><p><a href="https://github.com/Anshita-Bhasin">GitHub</a> | <a href="https://www.linkedin.com/in/anshita-bhasin/">LinkedIn</a> | <a href="https://twitter.com/anshita__bhasin">Twitter</a> | <a href="https://www.youtube.com/channel/UCtNHEcO_c9qpaUqIYSb98Rg">Youtube</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=690a95139ed7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/cypress-13-test-replay-and-cypress-dashboard-690a95139ed7">Cypress 13: Test Replay and Cypress Dashboard</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Safeguard Your Entry: Seamlessly Secure Vault Login with OIDC]]></title>
            <link>https://medium.com/propertyfinder-engineering/safeguard-your-entry-seamlessly-secure-vault-login-with-oidc-b3dbf20ab6fd?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/b3dbf20ab6fd</guid>
            <dc:creator><![CDATA[Jaydeep]]></dc:creator>
            <pubDate>Thu, 10 Aug 2023 12:40:09 GMT</pubDate>
            <atom:updated>2023-08-10T13:01:31.605Z</atom:updated>
            <content:encoded><![CDATA[<p>Vault, a trusted secret management tool, offers a robust way to store and protect confidential information. However, traditional login methods like Username/Password and token-based logins have their vulnerabilities. Compromising passwords or tokens could lead to unauthorized access, potentially exposing critical secrets. To address this concern, the article delves into the integration of Vault with OneLogin using OIDC.</p><p>In terms of infrastructure, we have discovered the most cost-effective solution available on the market — Fargate Spot, operating on an ECS cluster. This solution not only offers affordability but also seamlessly integrates with our existing environment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/802/1*TMmXOuhYV8osWqjBEzwAqw.png" /></figure><p>By leveraging Fargate for Vault, we get simplified deployment, cost efficiency, scalability, enhanced security, high availability, and seamless AWS integration, creating a robust platform for secure secret management.</p><p>To learn more about the installation and configuration of Vault on our infrastructure using ECS, please feel free to contact me through <a href="https://www.linkedin.com/in/jaydeep-singh-saini-4a17308a/">LinkedIn</a>. I would be happy to provide you with further details and insights.</p><h3>Setup Vault login via OIDC</h3><p>Before a client can interact with Vault, it must authenticate against an <a href="https://developer.hashicorp.com/vault/docs/auth">auth method</a> to acquire a token. This token has policies attached so that the behavior of the client can be governed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/761/1*bfxXP0SFgRHUqWgJjmj0fg.png" /></figure><p>Auth methods perform authentication to verify the user or machine-supplied information. Some of the supported auth methods are targeted towards users while others are targeted toward machines or apps.</p><p><strong>Onelogin Setup</strong></p><ol><li>Log in to your OneLogin admin portal.</li><li>Go to “Apps” and click “Add App” to add a new application.</li><li>Search for and select the “OpenID Connect (OIDC)” app.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ReyxDSKCH265wvL13iiBdA.png" /></figure><p>4. Provide a name for the app and click “Save”. You will be able to filter the app by name you provided.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZUmyxzHyZstLz9LCPD2ezA.png" /></figure><p>5. In the “Configuration” tab, enter the following information:</p><p>Login URL:<br><em>https://vault.example.com/ui/vault/auth?with=oidc</em></p><p>Redirect URI:<br><em>http://localhost:8250/oidc/callback,<br>https://vault.example.com/ui/vault/auth/oidc/oidc/callback</em></p><p>Post Logout Redirect URIs<br><em>https://vault.example.com/ui/vault/auth?with=oidc</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xPidrRsCqQnubbca8X7RDw.png" /></figure><p>Note: vault.example.com is just used as reference name, please replace it with your vault domain.</p><p>6. Under SSO Tab, Get the Client ID, Client Secret and Issuer URL</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UUnY2XkMBc9hW0vBEhahHA.png" /></figure><p>Due to security concerns, we have greyed out the client ID and issuer URL.</p><p>7. Next step is to create a new role, Go to OneLogin admin portal, <strong>Users &gt; Roles</strong>, and click <strong>New Role</strong>.</p><p>8. Give new role a name (in our case we gave Dev Vault) and select the applications it should include, then click <strong>Save</strong>.</p><p>9. Assigning Roles to Users: From <strong>Users &gt; Roles</strong>, open the role and go to <strong>Users</strong>. Enter one or more users into the <strong>Search for a user</strong> field and click <strong>Check. </strong>The user appears with a button<strong> Add to Role, </strong>this way you can add users manually.</p><p>Alternatively you can create mappings as well (for example: department ~ Engineering) to add all users under engineering department automatically.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ka7au-fniboleYiATRaO1g.png" /></figure><p>10. Now Go to Applications &gt; Vault Application that we created &gt; Access &gt; Roles, add new role we created above.</p><p>11. To verify, Go to Users tab and check users.</p><h3><strong>Vault Setup</strong></h3><ol><li>Login to Vault via Root Token</li><li>Click on Access → Enable New Method → Select OIDC</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/877/1*k0rRCEdqqG8CAyodYDiK_g.png" /></figure><p>3. OIDC Configurations: Check SSO Page of Onelogin and add Onelogin Issuer URL as OIDC discovery URL, Onelogin Client Key as OIDC Client Key, Onelogin Secret Key as OIDC Secret Key, Role as reader.</p><p>4. Create Vault Policies: Create the policy file named reader.hcl. This policy grants read and list capabilities to all paths in the KV secrets engine enabled at the secret path.</p><pre>tee reader.hcl &lt;&lt;EOF<br># Read permission on the k/v secrets<br>path &quot;/secret/*&quot; {<br>capabilities = [&quot;read&quot;, &quot;list&quot;]<br>}<br>EOF</pre><p>Select the Policies tab in Vault and then select Create ACL policy. Toggle Upload file sliding switch, and click Choose a file to select your reader.hcl file you authored, Click Create Policy to complete.</p><p>5. Create Vault Role: Click the Vault CLI shell icon (&gt;_) to open a command shell, Within the terminal, create the readerrole.</p><pre>export ONELOGIN_CLIENT_ID=&quot;CLIENT_ID_HERE&quot;<br><br>vault write auth/oidc/role/reader \<br>      bound_audiences=&quot;$ONELOGIN_CLIENT_ID&quot; \<br>      allowed_redirect_uris=&quot;https://vault.example.com/ui/vault/auth/oidc/oidc/callback&quot; \<br>      allowed_redirect_uris=&quot;http://localhost:8250/oidc/callback&quot; \<br>      user_claim=&quot;sub&quot; \<br>      token_policies=&quot;reader&quot;</pre><h3>Login with OIDC via UI</h3><ol><li>Sign out of the Vault UI if you are already logged in.</li><li>Select OIDC from the Method drop-down list.</li><li>In the Role, you can enter reader or since the default role is already set to “reader”, you can leave it blank.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/767/1*X5ZUjAZYIl0C4ZVm03iBOQ.png" /></figure><p>4. Click Sign in with OIDC Proivder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tq4jbLSDUVm2szXHDnJg1w.png" /></figure><p>5. Now, you should be logged in.</p><h3>Login with OIDC via CLI</h3><ol><li>Log in with the oidc method as role of a reader.</li></ol><pre>export VAULT_ADDR=&quot;https://vault.example.com&quot;<br>vault login -method=oidc role=&quot;reader&quot;</pre><p>2. When prompted, accept and authorize the Vault access to Onelogin App.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5j7uEJhfeZ5rBsDRLWc4Ag.png" /></figure><p>3. Back to terminal, you should see log in successful.</p><h3><strong>Conclusion</strong></h3><p>The seamless integration of Vault with OneLogin via OIDC offers a comprehensive solution to the challenges of securing sensitive information. By replacing traditional login methods with OIDC, you enhance your organization’s security posture and mitigate the risk of unauthorized access to critical secrets. By following the steps outlined in this article, you can establish a robust platform for secure secret management, contributing to the overall security and success of your organisation.</p><h3>Help and reference</h3><ul><li><a href="https://developer.hashicorp.com/vault/docs/auth/jwt">OIDC Auth Method</a></li><li><a href="https://developers.onelogin.com/openid-connect">Onelogin Openid Connect</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b3dbf20ab6fd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/safeguard-your-entry-seamlessly-secure-vault-login-with-oidc-b3dbf20ab6fd">Safeguard Your Entry: Seamlessly Secure Vault Login with OIDC</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Unveiling the Speed Mystery: Investigating Slow S3 Uploads from AWS EKS Pods]]></title>
            <link>https://medium.com/propertyfinder-engineering/unveiling-the-speed-mystery-investigating-slow-s3-uploads-from-aws-eks-pods-9bb676ef538e?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/9bb676ef538e</guid>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[s3]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[pods]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Yasitha Bogamuwa]]></dc:creator>
            <pubDate>Wed, 02 Aug 2023 07:33:31 GMT</pubDate>
            <atom:updated>2023-08-02T07:33:31.831Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*jbh4DejgvVX_9BEynRh3ew.png" /></figure><h4>The Problem</h4><p>At Property Finder, we have been using AWS EKS unmanaged clusters. Recently, our engineering teams have noticed an alarming issue with unreasonably slow S3 file uploads from their applications.</p><p>To investigate further, they conducted a comparison by running the same application on their local computers. Surprisingly, they observed that uploading a 10KB file to S3 took approximately 5 seconds on our EKS cluster. However, on their local machines, the identical upload process took approximately 1 second. Consistent testing revealed an average slowness factor of 5 when compared to the local computer uploads.</p><p>This noticeable increase in latency raised significant concerns, urging us to uncover the underlying root cause to identify possible solutions.</p><h4>Investigation</h4><p>To identify the issue and locate the bottleneck, we came up with the following plan:</p><p>1. Create a S3 bucket in the region where our EKS cluster is running.</p><p>2. Deploy a debug pod in the EKS cluster using the latest AWS CLI docker image.</p><pre># Debug pod configurations<br>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>name: debug<br>spec:<br>selector:<br>  matchLabels:<br>    app: debug<br>replicas: 1<br>template:<br>  metadata:<br>    labels:<br>      app: debug<br>  spec:<br>    containers:<br>    - name: debug<br>      image: amazon/aws-cli<br>      command: [&quot;sleep&quot;, &quot;infinity&quot;]</pre><p>3. Locate the EKS node where the debug pod is running.</p><pre>kubectl get pods -l=app=debug -o wide</pre><p>4. Create a 10KB file and upload it to the S3 bucket using AWS CLI from both the debug pod and EKS node where the debug pod is deployed. Measure the time taken for each upload.</p><pre># AWS CLI upload command<br>time aws s3 --debug cp 10kb.png s3://yasithab-debug-bucket/10kb.png</pre><h4>Identifying the Issue</h4><p>Based on the test conducted, it was discovered that uploading the 10KB file from the EKS node takes around 1 second, which is similar to uploads from a local computer. However, uploading the same file from the pod running on the same EKS node takes approximately 5 seconds. This indicates that there is something in between causing this issue, but the exact cause is still unknown.</p><pre># AWS CLI upload results from the EKS node where the debug pod is running<br>real   0m1.460s<br>user   0m0.908s<br>sys    0m0.085s</pre><pre># AWS CLI upload results from the debug pod<br>real   0m5.612s<br>user   0m0.956s<br>sys    0m0.073s</pre><p>As we have AWS enterprise support, we reached out to them with the test results and debug logs. They recommended provisioning a new EKS cluster and conducting the same test to isolate any other dependencies. However, we decided against this approach as we consider it unnecessary to set up a new cluster solely for debugging this issue. Therefore, we are currently on our own in resolving this matter, unfortunately.</p><p>With no clear direction at this stage, a possible course of action is to compare the AWS CLI debug logs for both node and pod uploads. This can be achieved by utilizing a file comparison tool. Initially, the focus was on investigating potential network delays by comparing the duration of the upload process.</p><p>The upload process began when the CLI displayed the following lines.</p><pre>MainThread - botocore.endpoint - DEBUG - Setting s3 timeout as (60, 60)<br>MainThread - botocore.utils - DEBUG - Registering S3 region redirector handler</pre><p>The upload process ended when the CLI displayed the following lines.</p><pre>upload: ./10kb.png to s3://yasithab-debug-bucket/10kb.png<br>Thread-1 - awscli.customizations.s3.results - DEBUG - Shutdown request received in result processing thread, shutting down result thread.</pre><p>Then, the duration from the beginning of the upload to the end of the upload event was calculated.</p><ul><li>In the node upload process, the start time was recorded as 2023–07–13 11:03:14,047, and the end time was recorded as 2023–07–13 11:03:14,161. Hence, the upload process took 114 milliseconds.</li><li>In the pod upload process, the start time was recorded as 2023–07–13 10:57:54,740, and the end time was recorded as 2023–07–13 10:57:54,828. Hence, the upload process took 88 milliseconds.</li></ul><p>The almost identical upload times indicate that this issue is not caused by network latency.</p><p>Upon reviewing the logs further, it was observed that in the pod upload debug log, most of the time was spent on establishing the connection to the Instance Metadata Service (IMDS) endpoint. This process took around 1 second and was attempted three times, totaling approximately 4 seconds. On the other hand, the initialization of the connection to the IMDS endpoint from the EKS node where the debug pod is deployed, only took 190 milliseconds.</p><pre># From the EKS node where the debug pod is deployed - 190 milliseconds<br>2023-07-13 11:03:13,857 - MainThread - botocore.utils - DEBUG - IMDS ENDPOINT: http://169.254.169.254/<br>2023-07-13 11:03:14,047 - MainThread - botocore.endpoint - DEBUG - Setting s3 timeout as (60, 60)</pre><pre># From the debug pod - 4 seconds and 259 milliseconds<br>2023-07-13 10:57:50,481 - MainThread - botocore.utils - DEBUG - IMDS ENDPOINT: http://169.254.169.254/<br>2023-07-13 10:57:54,740 - MainThread - botocore.endpoint - DEBUG - Setting s3 timeout as (60, 60)</pre><p>When comparing the total time taken from the debug pod (5 seconds and 612 milliseconds) with the time taken for establishing the connection to the Instance Metadata Service (IMDS) endpoint from the debug pod (4 seconds and 259 milliseconds), a difference of 1 second and 353 milliseconds is observed. Remarkably, this difference closely matches the time taken from the EKS node upload results.</p><p>Hooray! The Instance Metadata Service (IMDS) has been identified as the bottleneck. However, the next step is to understand why this is happening and determine how to resolve it.</p><h4>What is IMDS and What it does here?</h4><p>The AWS Instance Metadata Service (IMDS) is a service that allows EC2 instances to access information about themselves. This information includes details like the instance ID, instance type, network configurations, identity credentials, security groups, and more. Applications running on EC2 instances can use IMDS to retrieve dynamic information about the instance. IMDS has two versions available.</p><ul><li>Instance Metadata Service Version 1 (IMDSv1) — a request/response method.</li><li>Instance Metadata Service Version 2 (IMDSv2) — a session-oriented method.</li></ul><p>By default, you have the option to use either IMDSv1 or IMDSv2, or both. The instance metadata service differentiates between IMDSv1 and IMDSv2 requests based on the presence of specific PUT or GET headers, which are exclusive to IMDSv2. If you configure IMDSv2 to be used in the <strong>MetadataOptions</strong>, IMDSv1 will no longer function.</p><p>To retrieve the <strong>MetadataOptions</strong> for an EKS node, use the following command. Replace &lt;EKS_NODE_INSTANCE_ID&gt; with the specific instance ID of the EKS node you wish to retrieve the <strong>MetadataOptions</strong> for.</p><pre>aws ec2 describe-instances --instance-ids &lt;EKS_NODE_INSTANCE_ID&gt; --query &quot;Reservations[].Instances[].MetadataOptions&quot;</pre><p>The above command will give an output similar to the following:</p><pre>[<br>    {<br>        &quot;State&quot;: &quot;applied&quot;,<br>        &quot;HttpTokens&quot;: &quot;optional&quot;,<br>        &quot;HttpPutResponseHopLimit&quot;: 1,<br>        &quot;HttpEndpoint&quot;: &quot;enabled&quot;,<br>        &quot;HttpProtocolIpv6&quot;: &quot;disabled&quot;,<br>        &quot;InstanceMetadataTags&quot;: &quot;disabled&quot;<br>    }<br>]</pre><p>In the output, it shows that the <strong>HttpTokens</strong> attribute is set to optional.</p><p>When the <strong>HttpTokens</strong> is set to optional, it sets the use of IMDSv2 to optional. You can retrieve instance metadata with or without a session token. Without a token, IMDSv1 role credentials are returned, and with a token, IMDSv2 role credentials are returned.</p><p>On the other hand, when <strong>HttpTokens</strong> is set to required, IMDSv2 becomes mandatory. You must include a session token in your instance metadata retrieval requests. In this case, only IMDSv2 credentials are available; IMDSv1 credentials cannot be accessed.</p><p>IMDSv2 is an improved version of instance metadata access that adds an extra layer of security against unauthorized access. To use IMDSv2, a PUT request is required to establish a session with the instance metadata service and obtain a token. By <strong>default</strong>, the response to PUT requests has a response <strong>hop limit</strong> of <strong>1</strong> at the IP protocol level.</p><p>However, <strong>this limit is not suitable for containerized applications</strong> on Kubernetes that operate in a separate network namespace from the instance. EKS managed node groups that are newly launched or updated will have a metadata token response hop limit of 2. However, in the case of self-managed nodes like ours, the default hop limit is set to 1. Therefore, setting the <strong>HttpPutResponseHopLimit</strong> to <strong>2</strong> in our EKS is mandatory for retrieving InstanceMetadata over IMDSv2.</p><h4>How does the upload work with HttpPutResponseHopLimit set to 1 despite the slow upload speed?</h4><p>When the HttpTokens attribute is set to optional, the AWS CLI/SDK automatically use IMDSv2 calls by default. If the initial IMDSv2 call does not receive a response, the CLI/SDK retries the call and, if still unsuccessful, fallback to using IMDSv1. This fallback process can introduce delays, especially in a container environment.</p><p>In a container environment, if the hop limit is set to 1, the IMDSv2 response does not return because accessing the container is considered an additional network hop. To avoid the fallback to IMDSv1 and the resulting delay, it is recommended to set the hop limit to 2 in a container environment.</p><h4>Resolve the issue</h4><p>According to AWS documentation, containerized applications running on EKS require the EKS node <strong>HttpPutResponseHopLimit</strong> in MetadataOptions to be set to <strong>2</strong>. To configure this, you can use the following command, replacing &lt;EKS_NODE_INSTANCE_ID&gt; with the instance ID of the specific EKS node you want to retrieve MetadataOptions for.</p><pre>aws ec2 modify-instance-metadata-options --instance-id &lt;EKS_NODE_INSTANCE_ID&gt; --http-endpoint enabled --http-put-response-hop-limit 1</pre><p>In many cases, EKS nodes are part of AWS auto scaling groups, making manual modification of instance metadata difficult. To configure Instance Metadata Service (IMDS) for an auto scaling group, you need to modify its associated launch configurations.</p><p>To set the <strong>HttpPutResponseHopLimit</strong> for all instances associated with the launch configuration, go to the <strong>Additional configuration</strong> section under <strong>Advanced details</strong> of the template. Set the <strong>Metadata response hop limit</strong> to <strong>2</strong>. If no value is specified, the default is set to 1.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Mw7MbZm5TN_OTscFkeDhCQ.png" /></figure><p>When using Terraform to provision your infrastructure, you can utilize the aws_launch_template resource to modify instance metadata in the following manner.</p><pre>resource &quot;aws_launch_template&quot; &quot;foo&quot; {<br>  name = &quot;foo&quot;<br><br>  metadata_options {<br>    http_endpoint               = &quot;enabled&quot;<br>    http_tokens                 = &quot;optional&quot;<br>    instance_metadata_tags      = &quot;disabled&quot;<br>    http_put_response_hop_limit = 2<br>  }<br>}</pre><p>After implementing the <strong>HttpPutResponseHopLimit</strong> modifications, we conducted the same tests as in the investigation phase. The results of both the EKS node and debug pod uploads were nearly identical.</p><pre># AWS CLI upload results from the EKS node where the debug pod is running<br>real    0m1.310s<br>user    0m0.912s<br>sys     0m0.078s</pre><pre># AWS CLI upload results from the debug pod<br>real    0m1.298s<br>user    0m0.931s<br>sys     0m0.082s</pre><h4>Conclusion</h4><p>In conclusion, our investigation into the significantly slow S3 file uploads from applications running on AWS EKS clusters revealed that the Instance Metadata Service (IMDS) was the root cause of the issue. By comparing upload times from EKS nodes and pods, we identified a delay in establishing the connection to the IMDS endpoint from within the pods. This delay was not present when uploading directly from the EKS nodes.</p><p>To resolve this issue, it is necessary to set the <strong>HttpPutResponseHopLimit</strong> in the MetadataOptions to <strong>2</strong> for EKS nodes. This can be achieved by modifying the associated launch configurations for auto scaling groups or using the aws_launch_template resource in Terraform.</p><p>By setting up the <strong>HttpPutResponseHopLimit</strong> to <strong>2</strong>, we can eliminate the latency and significantly improve the speed of file uploads to S3 from AWS EKS pods. This resolution will enhance the overall performance and efficiency of our applications on the EKS cluster.</p><h4>References</h4><ol><li><a href="https://aws.amazon.com/about-aws/whats-new/2020/08/amazon-eks-supports-ec2-instance-metadata-service-v2/">Amazon EKS now supports EC2 Instance Metadata Service v2</a></li><li><a href="https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html">Describe EC2 MetadataOptions</a></li><li><a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#imds-considerations">Retrieve instance metadata</a></li><li><a href="https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-instance-metadata-options.html">Modify Instance Metadata</a></li><li><a href="https://github.com/hashicorp/terraform-provider-aws/issues/23110">Issue with EC2 Instance Metadata running inside Container</a></li><li><a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/create-launch-config.html#launch-configurations-imds">Configure the instance metadata options for Auto Scaling Groups</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9bb676ef538e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/unveiling-the-speed-mystery-investigating-slow-s3-uploads-from-aws-eks-pods-9bb676ef538e">Unveiling the Speed Mystery: Investigating Slow S3 Uploads from AWS EKS Pods</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[LET’S DETOX]]></title>
            <link>https://medium.com/propertyfinder-engineering/lets-detox-ba16eeba6022?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/ba16eeba6022</guid>
            <category><![CDATA[mobile-automation-testing]]></category>
            <dc:creator><![CDATA[Cassandra D'Mello]]></dc:creator>
            <pubDate>Thu, 30 Jun 2022 12:07:30 GMT</pubDate>
            <atom:updated>2022-06-30T12:07:30.592Z</atom:updated>
            <content:encoded><![CDATA[<h4>What is Detox?</h4><p>Detox — a peculiar name. A quick google search on Detox gives you this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*VLrjppRpYkDQzzsp" /></figure><p>But that’s not what we are here to talk about.</p><p>Here, we talk about the Javascript End-to-End App Testing and Automation framework created and maintained by Wix. It can be built into the test application so that the test execution begins with the app launch.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*KiMsofiSGy6FYMjP" /></figure><p>In this article we’ll take a look at app automation with Detox, why it is a strong contender to traditional app automation frameworks like Appium and its pros and cons.</p><p>We’ll also have a brief look into the prerequisites needed and a sample test case.</p><h4>Is this article relevant to you?</h4><p>If you are a QA tester looking at options to automate your mobile app, or even an app developer looking to write automation scripts for the app you are building, this article is for you!</p><h4>We have Appium, so why Detox?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CSRFhzY0OZPD_JAu" /></figure><p>Our search for an alternative app test automation framework began due to the flakiness of Appium like false failures and failure to locate page objects on time.</p><p>Appium is a black box testing tool with no access to the code it is testing because of which we need to add sleep statements. This makes it slow and flaky.</p><p>On the contrary, the Detox philosophy is “Gray Box Testing”, where it knows about the internals of the test product. This is what makes it a strong contender to Appium and the main reason we decided to explore it for the myCRM app automation.</p><h4>What makes Gray box testing tools like Detox better than Appium?</h4><ul><li><em>More stable scripts<br></em>Gray box testing tools like Detox synchronises with the test app and can monitor the network requests, JS threads, timers and page loads. This eliminates the need for “sleep” statements and makes the test more stable.</li><li><em>Faster scripts<br></em>Gray box testing tools are 5–10 times faster than black box testing tools.</li><li><em>Access to app code<br></em>Detox can access the code and data of the app, eliminating the need for writing additional code to do so.</li></ul><h4>What are the highlights of Detox?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*z0xr53EE4i68Qtwv" /><figcaption>Source: <a href="https://wix.github.io/Detox/"><em>https://wix.github.io/Detox/</em></a></figcaption></figure><h4>Sounds too good to be true, doesn’t it?</h4><p>Detox is not without its limitations. Some of which are listed below:</p><ul><li>No real device testing support for IOS,</li><li>Not a large online community for support which is so important,</li><li>It does not support Web views and Hybrid,</li><li>It’s capabilities are not as wide as Appium.</li></ul><h4>What are the prerequisites to run Detox?</h4><ol><li>Homebrew: Homebrew is an open source software package management system that simplifies the installation of software on the macOS.</li><li>Node.js 8.3.0 or above: Node.js is a JavaScript runtime environment Detox will run on.</li><li>Applesimutils: This is a collection of utils for the Apple simulator</li><li>Detox command line tools.</li></ol><h4>What does a Detox test look like?</h4><p>This is a sample Login code snippet:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XF8AeTaU6IxS-RpX" /></figure><p>As seen above the syntax is easily readable. We can easily write synchronous tests using await/async statements that:</p><ul><li>Keep track of all network requests that are currently in-flight and wait until they complete,</li><li>Keep track of pending animations and wait until they complete,</li><li>Keep track of timers and wait until they expire or are cancelled,</li><li>Keep track of the React Native operations.</li></ul><p>Open the simulator and run the test script:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/791/0*DuzUY36xkeK1uJKb" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*MdcIKOmh6Zbd_grQ" /></figure><h4>Summary</h4><p>In summary, Detox is a handy tool for app test automation considering the speed and stability of the execution of tests. However, the lack of online support is currently the biggest detriment to its adoption.</p><p>We are still in the early stages of implementing it in our project and will have a better idea of its capabilities as we proceed.</p><p><strong>You can read up further about Detox as follows:</strong><em> </em><a href="https://reactnativetesting.io/e2e/setup/"><em>https://reactnativetesting.io/e2e/setup/</em></a></p><p><a href="https://github.com/wix/Detox"><em>https://github.com/wix/Detox</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ba16eeba6022" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/lets-detox-ba16eeba6022">LET’S DETOX</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Go and MySQL: Setting up Connection Pooling]]></title>
            <link>https://medium.com/propertyfinder-engineering/go-and-mysql-setting-up-connection-pooling-4b778ef8e560?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/4b778ef8e560</guid>
            <category><![CDATA[pool]]></category>
            <category><![CDATA[go]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[mysql]]></category>
            <dc:creator><![CDATA[TiGran Khanagian]]></dc:creator>
            <pubDate>Thu, 23 Jun 2022 13:13:57 GMT</pubDate>
            <atom:updated>2022-06-23T20:56:56.048Z</atom:updated>
            <content:encoded><![CDATA[<p>When writing code under high load conditions, one can often encounter problems related to the database. I used to launch different high load services in Go with MySQL as a data storage. During the maintenance of these services I had to solve various problems of working with the database. Misusing connection pooling and prepared statements, improper queries… All this affects performance and fault tolerance. Since then I have some tips to share with you to make your Go code more reliable in terms of MySQL usage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/781/1*CQO_w0dI8zzJCcetyahvLA.png" /></figure><p>One of the most common problems you may encounter is misconfiguration. Through this blog post, I will explain basic concepts to better understand the cause of problems and provide you with a compilation of best practices in Go and MySQL interaction.</p><p>So I’ll share some advice about configuring connections to MySQL. We’ll go through the main points that you need to pay attention to when working with MySQL using Go language.</p><ul><li>We’ll cover <strong>the basics of client-server protocol MySQL</strong>, its basic structure and operation principle.</li><li>Then we’ll move on to the Go part and <strong>will analyze the implementation of the connection pooling</strong>.</li><li>We will go from <strong>configuring connections to making requests</strong> simultaneously looking at the driver code.</li></ul><h3>MySQL Client-server protocol</h3><p>It is a half-duplex protocol, in other words, it is synchronous. It means you can either send a request or accept it.</p><p>After sending a command to the server the client should wait for a response before initiating another action . At the same time the message should be received entirely, the client cannot break it off abruptly, unless the connection is interrupted.</p><p>All data transmitted over the protocol is packed into packets. There are predefined packet types on the server and client sides and they can exchange these packets between each other.</p><p>Generally the client sends a request in one packet, while the server may respond with several packets. And even if the client needs only part of the packages, it still has to receive all of them.</p><p>In this protocol, TCP will be used as a transport that is used by the client and server to exchange these same packets in binary.</p><p>The MySQL protocol has two main phases:</p><h4>Connection phase</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/780/0*ttM0ZiTS-C2t96Ae" /></figure><p>Once TCP connection is established, the MySQL server sends a <a href="https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake"><em>packet with a handshake to the client</em></a> after which parameters are exchanged. For example, a client can request an SSL connection, and then send <a href="https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse"><em>a response packet to the server for a handshake</em></a>.<br>After a successful first phase the protocol enters <strong>the command phase</strong> mode.</p><h4>Command phase</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/781/0*NS5A_creyHCd8pW3" /></figure><p>In this phase the client takes the initiative and sends <a href="https://dev.mysql.com/doc/internals/en/command-phase.html"><em>command packets to the server</em></a>. These include <strong>queries</strong>, <strong>prepared expressions</strong>, <strong>stored procedures</strong>, and <strong>replication commands</strong>. The server processes client requests and responds with a result.</p><p>We can look at the MySQL protocol. To do this the database has a special plugin that displays the trace. It is convenient to use for testing (not production solutions), so it is disabled by default. To enable it you need to create the database server using the <a href="https://dev.mysql.com/doc/extending-mysql/5.7/en/test-protocol-trace-plugin.html"><em>WITH_TEST_TRACE_PLUGIN</em></a> option.</p><p>You can watch the trace output in the terminal after connecting to the server. Here’s what it looks like.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NaYeuI3CEIh4vy7h" /></figure><p>Another way to look at the data being transmitted is to use the <strong>ngrep</strong> utility on the client:</p><pre>sudo ngrep -x -q -d any port 3306</pre><p>The output between the client and the server will look as follows.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1015/0*sDFxsRdcWuB_05oQ" /></figure><h3>Libraries for GO</h3><p>The standard library contains only the main interface — <a href="https://golang.org/pkg/database/sql/"><em>database/sql</em></a> for all sql or sql-like databases. The language maintainers left the implementation of protocols for specific databases to the third-party developers. That is why we will use its <a href="https://github.com/go-sql-driver/mysql"><em>official go-mysql driver</em></a>, which is a separate package itself.</p><p>The standard sql interface package uses a connection pooling for database connections. This is because MySQL protocol requests occur synchronously — each client can execute the next request only after it completes the previous one.</p><p>But are there any other options else?</p><h4>One connection</h4><p>The first thing that might come to mind is to use one global connection for the entire service. It is clear that as a result all new requests will wait until the connection is free. This will be a bottleneck and our service may hang for a long time.</p><h4>Connection per each request</h4><p>You can create a new connection on each request, closing it on completion.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/780/0*UasVEKOr24Bqmjr1" /></figure><p>While it solves the main issue of waiting for a connection, there are some other challenges related to its use.</p><p><strong>First, </strong>we won’t be able to control the growth of connections to our database. The number of our connections will directly depend on the number of requests — i.e. how many connections the service will open will depend on how many requests will come. And it is not good for the database. In a normal mode, we may not have problems, but at times of peak loads you can reach the maximum possible number of connections from the database, and it will simply stop responding. There will be errors when connecting to the database both in our service and in all others that use it.</p><p><strong>Second, </strong>each time we will be forced to go through the first phase of connecting to the MySQL server, in which TCP connection, handshake and authorization are established. Compared to the command phase, this one is more time consuming as we will spend extra time creating a new connection each time.</p><p>Thus, the connection pool solves all these problems to one degree or another.</p><h3>Connection pooling</h3><p>Pools help us control the total number of connections that a service can use to access the database. Thus we can secure both the database and minimize the number of passes of the first phase of the connection. Because as a rule in the pool we have connections prepared in the command phase, with the first phase of the connection already passed.</p><h4>Pool initialization</h4><p>Let’s start with initializing our pool and see what happens in the code directly from the documentation of the <strong>go-sql-driver</strong> package.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9ad8afed9678af71c95342bbd069fb4b/href">https://medium.com/media/9ad8afed9678af71c95342bbd069fb4b/href</a></iframe><p>At the very beginning when importing the <strong>go-sql-driver</strong> the mysql protocol is registered.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b9543eb72a8d0c7524ec234addffcbfb/href">https://medium.com/media/b9543eb72a8d0c7524ec234addffcbfb/href</a></iframe><p>Then when calling the <em>Open</em> method, we say that we want to open a pool that will use the protocol called mysql (first parameter) while connecting, that is implemented in the go-sql-driver package with the configurations passed using the second parameter. After that the methods for configuring our pool are called, which we will discuss at a later stage.</p><h3>Pool view</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d009affa5297e53de59701286557402a/href">https://medium.com/media/d009affa5297e53de59701286557402a/href</a></iframe><p>This structure represents our connection, outlining various structure fields required for configurations. For example, the <strong>freeConn</strong> field, which is a slice of links to connections using our chosen protocol (in fact, this field represents the set of our free connections itself). Or the <strong>connRequests</strong><em> </em>field which is used to request a new connection, etc.</p><p>Calling the Open method results in the creation of a new DB structure.</p><h3>Creating an empty pool</h3><p>Inside it the OpenDB method is called, in which the structure with the initial data is initialized.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2cb98ec95efc694818b5294bff1386a4/href">https://medium.com/media/2cb98ec95efc694818b5294bff1386a4/href</a></iframe><p>As you can see from the code the pool is initialized empty. It means that at this stage <strong>we have not yet established any connection</strong> to the database. Therefore, if you have incorrect data in the configuration (for example an incorrect login or a password) when you call the <em>Open</em> method, you won’t know about it yet.</p><p>So, we have created a pool, and after that it must be configured.</p><h3>Pool configuration</h3><p>The following methods are mainly used to configure a pool.</p><ul><li><a href="#24bd">SetMaxOpenConns()</a></li><li><a href="#fecb">SetMaxIdleConns()</a></li><li><a href="#0ffb">SetConnMaxLifetime()</a></li><li><a href="#556f">SetConnMaxIdleTime()</a></li></ul><p>Let’s see them in more detail.</p><h3>Maximum number of connections</h3><p>Using the <strong>SetMaxOpenConns()</strong> method we set the maximum possible number of open connections to the database from our pool. <strong>Be careful</strong> — by default this value is 0, which means unlimited number of connections. This can lead to the situation we talked about above, when every request to your service will open a new connection.</p><p>What’s the time when the connections are created? Usually after the pool is initialized, the ping method is called, which creates a connection to the database. At this stage, you can assess whether our configuration is correct or not.</p><pre>err = db.Ping()</pre><h4>Connection creation strategies</h4><p>Before each request our pool tries to get a connection by calling -</p><pre>conn(ctx context.Context, strategy connReuseStrategy)</pre><p>The method implements 2 strategies for creating a connection. <strong>AlwaysNewConn</strong> always creates a new connection, and <strong>cachedOrNewConn</strong> first tries to take a free connection from the pool, if any.</p><p>If there are no connections in the pool, then the method will create a new one. If it is impossible to create a new connection due to the limits set on the number of open connections, then a request will be created to open a new connection and it will wait for its execution.</p><p>The connection received using this method immediately goes into use and is marked as busy, then we are ready to make our requests. After we release this connection it will try to return to the pool.</p><h3>Pool size limitation</h3><p>Using the <strong>SetMaxIdleConns()</strong> method we adjust the maximum number of free connections that can be stored in the pool and wait until they are used. By default you can put up to two connections in the pool.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/94fbc8e101a96662cc72104226cb374b/href">https://medium.com/media/94fbc8e101a96662cc72104226cb374b/href</a></iframe><p>The <strong>«query»</strong> method is one of the most frequently called methods for performing queries, in which the connection is released after use and an attempt is made to put it back into the pool of free connections. In the specified code the <strong><em>dc.releaseConn</em></strong> function is responsible for this. If the pool already has the maximum number of connections, then the freed connection will be closed.</p><p>However, if the connections are still closed on time, it can still be configured.</p><h3>Connection lifetime</h3><p>The <strong>SetConnMaxLifetime() </strong>method is responsible for determining the lifetime of the connection in the pool from the moment it was created.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8a1422db0bc0a206b7045dab23cb189c/href">https://medium.com/media/8a1422db0bc0a206b7045dab23cb189c/href</a></iframe><p>Age check is performed every time you try to get a connection from the pool. connectionCleaner also monitors the age. It simply closes expired connections by looping through them and checking the lifetime.</p><p>But wait there’s more. Starting with Go version 1.15 you can specify a connection time-out.</p><h3>Pool time-out</h3><p>The <strong>SetConnMaxIdleTime()</strong> method sets the maximum amount of time a connection can be idle in the pool. This setting is very similar to the previous one, but the main difference is that the connection lifetime is counted from the date of its creation, and the time-out in the pool is counted from the moment when this connection was returned to the pool.</p><p>After this time has elapsed the connection will also be closed.</p><h3>Returning a connection to the pool</h3><p>As we have already said, when executing a request the connection is taken from the pool or created if there is nothing in the pool, after which it is marked as busy. After making requests we <strong>must release it</strong>.</p><p>When we receive data for our request we get back a structure with the results of Rows, which also contains our connection.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/072cdbc5b5c6de43ce3b20c6cfcaf51a/href">https://medium.com/media/072cdbc5b5c6de43ce3b20c6cfcaf51a/href</a></iframe><p>When the <strong>Close()</strong> method is called, the connection is released and an attempt is made to put it in the pool or close it if there is no free space in the pool. Therefore, writing code as in the example above is not good. <strong>Be sure to call Close at least in defer.</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/98324cb9738b358d55c049eb500486e1/href">https://medium.com/media/98324cb9738b358d55c049eb500486e1/href</a></iframe><p>If you do not release connections, then they will simply hang with the «busy» status, consume memory and clog the number of open connections. As a result we can get an empty pool, since all connections will be considered busy, but at the same time we won’t be able to create a new connection, as we have reached the limit of maximum open connections. This will lead to a situation in which we can neither create new connections nor use existing ones.</p><p>But it is even better to do this as follows.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9beca9b1b1ea30ceb5a4aa85e7969842/href">https://medium.com/media/9beca9b1b1ea30ceb5a4aa85e7969842/href</a></iframe><p>When we initiate <strong>Scan()</strong>, Go tries to convert the bytes that came from MySQL to the data types passed in the parameters. And note that the request execution method is tied to the context. If the context is reset during the execution of <strong><em>Scan()</em></strong> the data may be corrupted. This problem is described in considerable detail in <a href="https://github.blog/2020-05-20-three-bugs-in-the-go-mysql-driver/">this article, section «The race»</a>.</p><p>You can catch this error explicitly calling the <strong>Close</strong> method and checking for an error. In defer we leave Close to make sure that if some panic occurs, the connection will return to the pool.</p><p>Next, I will use synthetic examples to show how all this affects real requests. But before that, let’s look at one more interesting nuance that affects our requests.</p><h3>Interpolation of parameters</h3><p>Generally the placeholders are used to make requests with parameters to avoid possible sql injections.</p><pre>db.QueryRow(“SELECT * FROM client WHERE id=?”, id)</pre><p>But this way of making requests can work differently depending on the settings.</p><p>The parameter <em>interpolateParams=true/false</em> is also supported as a MySQL connection configuration. By default its value is false, which is the same as a non-passed parameter.</p><p>If it is false, to make the above request a command is sent to the database server to prepare the expression (<a href="https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html">Prepared Statements</a>), after which a new command will be sent to execute the prepared expression.</p><p>If we have a large and complex request with numerous placeholders that will be executed several times in a method (for example, when creating batches of work), then the prepared expressions can speed up our work. Having performed the preparation once on the MySQL server, we use the prepared request without spending resources on parsing it each time.</p><p>If interpolation is enabled, i.e. set to true, the placeholders are replaced by values in the go library code. But if you do not enable interpolation of parameters for regular one-time requests, we will receive two TCP requests to the MySQL server instead of one (not counting the connection itself).</p><p>Request with the parameter <strong>interpolateParams=false</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0r2TPHM5Ymjw_cWu" /></figure><p>The same request with <strong>interpolateParams=true</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*uE16sMzvl4xpYbT2" /></figure><h3>Connection Pooling in a Real Sense</h3><p>Let’s see some pool configuration examples in action. I will loop through the request <em>“SELECT SLEEP(2);”</em> to a MySQL database and see what happens with the connections. In the specified code there is a pause of one second after each request. This results in connections not having the time to be reused, so we can see them on an informational basis.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5eed78c33184fd5a8b1848bc284066b1/href">https://medium.com/media/5eed78c33184fd5a8b1848bc284066b1/href</a></iframe><p>And this will lead us to the situation we talked about <a href="#18bf">above</a>. When each call of our method will block the connection on itself, the rest of the requests will wait until the connection is released. Please note that this takes 11 seconds.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*co4GgHjkfgKXda0-" /></figure><p>Then I will make a change <strong>maxOpenConns := 0:</strong></p><pre>maxLifeTime := time.Second * 10</pre><pre>maxOpenConns := 0</pre><pre>maxIdleConns := 0</pre><pre>db := NewPool(maxLifeTime, maxOpenConns,maxIdleConns)</pre><p>This will lead us to our <a href="#35d3">second</a> case, when each request will create a new connection to the base. As a result we will get an error when trying to connect due to the restriction on the number of connections on the database side.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YNrTxMkUbOkqF2aX" /></figure><p>Now we’ll set <strong>maxOpenConns=3</strong>, as we have some restrictions.</p><pre>maxLifeTime := time.Second * 10</pre><pre>maxOpenConns := 3</pre><pre>maxIdleConns := 0</pre><pre>db := NewPool(maxLifeTime, maxOpenConns, maxIdleConns)</pre><p>In this case we already have the opportunity to open three connections that can work in parallel. And the same five requests took<strong> 6.2 seconds</strong> instead of 11 seconds as in the first case. But at the same time we see that for each request, we go through the stage of connecting to the database again.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*t0uejDN4Bwg0snJa" /></figure><p>Let’s configure the pool to minimize connections. Let’s set <strong>maxIdleConns=3:</strong></p><pre>maxLifeTime := time.Second * 10</pre><pre>maxOpenConns := 3</pre><pre>maxIdleConns := 3</pre><pre>db := NewPool(maxLifeTime, maxOpenConns, maxIdleConns)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*sakLw1yhKEEDg7Lc" /></figure><p>As a result we go through the connection stage only 3 times and put the prepared connections into the pool. On subsequent requests to the database, they are taken from the pool with the authorization phase already passed, and you just have to send the command. And in general requests are made faster.</p><h3>Let’s sum it up</h3><ol><li>Never leave the connection pool settings at default, you should always customize it to suit your needs.</li><li>Set maxOpenConns below the configured connection limits on the database side</li><li>maxOpenConns = 0 means unlimited number of connections</li><li>If your MySQL server has timeouts configured for idle connections and they are closed on the database side, then there is no need to use maxLifeTime, as the go driver will detect the break and will make the connection again</li><li>Choose the value of maxLifeTime to minimize the creation of connections during peak loads on your service, and when the load drops, connections should not hang idle for a long time</li><li>Do not forget the method SetConnMaxIdleTime (with go 1.15). Using this method you can reduce the connection timeout in the pool by deleting it if no one is using it. Thus you can save on the number of open connections in the database and reduce memory consumption in the service.</li><li>Always release a connection after the request (rows.Close()). Using some methods it is done automatically, but it’s okay if you repeat the Close() call to be safe.</li><li>If you use multiple pools for the same database (for example, a read pool and a write pool), then the total number of maxOpenConns of these two pools must be less than the configured connection limits on the database side.</li><li>If you scale your service, don’t forget that open connections will also increase. If you add three instances, then make sure that the sum of maxOpenConns of all three is less than the configured connection limits on the database side.</li><li>Do not forget about various proxies that, including its timeouts and restrictions, can stand between you and your database. Consider intermediary settings too</li><li>Consider special aspects of your service. Take into account the nature of the load and adjust the pool settings.</li><li>Do not forget about monitoring, and also keep checking the connection pool.</li></ol><p>Thank you for taking the time to read my article. If you have any questions, please leave a comment below and I will be happy to answer.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4b778ef8e560" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/go-and-mysql-setting-up-connection-pooling-4b778ef8e560">Go and MySQL: Setting up Connection Pooling</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Top Golang Frameworks for Gophers]]></title>
            <link>https://medium.com/propertyfinder-engineering/top-golang-frameworks-for-gophers-45843d454b63?source=rss----18960d28ee42---4</link>
            <guid isPermaLink="false">https://medium.com/p/45843d454b63</guid>
            <dc:creator><![CDATA[Sreejaa Venugopal Nair]]></dc:creator>
            <pubDate>Wed, 25 May 2022 06:50:24 GMT</pubDate>
            <atom:updated>2022-05-25T17:37:44.149Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fFnOIPF_SsP03O91ZcYCYw.png" /></figure><p>Golang (Go) is a general purpose programming language by Google. Many Developers have embraced Go because it’s fast, efficient, offers concurrency, garbage collection, memory safety, and a structural typing system.</p><p>According to the 2022 Stack Overflow Developer survey, Go is one of the best-paid technologies and the second most <a href="https://insights.stackoverflow.com/survey/2021#technology-top-paying-technologies"><strong><em>“demanded” backend programming</em></strong></a> language.</p><p>Popular Companies that have already embraced Go include the following:</p><p><strong><em>Google, YouTube, Apple, Amazon, Facebook, Netflix, Dropbox, Docker, BBC, IBM, Twitter, Spotify, Soundcloud, Uber, SendGrid, and of course Property Finder…</em></strong></p><p><strong><em>Why Go frameworks?</em></strong></p><p>Finding the right web framework is essential as it will save precious time and resources while developing an application. A framework also supports the development process allowing Developers to use their energy on building the features and functionality rather than having to write the base code.</p><blockquote><em>Go frameworks provide many advantages to a development team:</em></blockquote><ul><li><em>Eliminating code redundancy and duplication</em></li><li><em>Better code security</em></li><li><em>Helping to improve consistency in code</em></li><li><em>Fewer bugs</em></li><li><em>Improving reliability</em></li><li><em>Easier testing and debugging processes</em></li><li><em>Improving programming productivity</em></li><li><em>Helping to establish better programming practices</em></li><li><em>Stronger documentation</em></li></ul><p><strong><em>Are you planning to develop using Go and confused which framework to choose? Here is a list of popular Go Frameworks:</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SDP-D3GDZ4UUV00WzEzniw.png" /><figcaption>Top GO Web Frameworks (according to <strong>stars</strong> on <strong>GitHub</strong>)</figcaption></figure><p><strong><em>Now, let’s delve into each one of these frameworks individually looking at their main features, pros and cons:</em></strong></p><h3><strong><em>1. Gin Gonic</em></strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*Lk95pTISZaOX03TYLhlDkA.png" /></figure><p><a href="https://github.com/gin-gonic/gin">Gin </a>is considered a very minimalistic framework. It was built based on <a href="https://github.com/go-martini/martini">Martini</a>. Gin Gonic focuses on significant features libraries, uses HTTP router, the quickest HTTP router of Go language which makes it 40x faster and quicker than Martini.Gin has made monitoring or debugging very simple. Gin is highly suitable for building extremely high-performing Rest Apis.</p><p><strong><em>Documentation</em></strong><em> : </em><a href="https://gin-gonic.com/docs/"><strong><em>Gin Gonic Documentation</em></strong></a></p><p><strong><em>Significant features:</em></strong></p><ul><li><strong><em>Speed : </em></strong><em>Gin is a fast framework because of its route grouping and small memory. It’s built on HttpRouter, a lightweight, high-performance HTTP request router. Gin has a low memory footprint and it provides faster performance.</em></li><li><strong><em>Great error management and crash recovery : </em></strong><em>Gin makes it easy to track errors occurring during an HTTP request.</em></li></ul><p><em>When an error is encountered in a HTTP request Gin documents the errors:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mRcNNWwx1oMQK6iZLPqoCA.png" /></figure><ul><li><strong><em>Easily Extendable : </em></strong><em>It’s also very easy to create middleware which can be plugged into the request pipeline:</em></li></ul><p><em>Creating a router and adding middlewares:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nyFXyD4VMD713uKKxpu0Lw.png" /></figure><ul><li><strong><em>Built-in rendering:</em></strong></li></ul><p><em>Gin provides an easy to use API for JSON, XML and HTML rendering.</em></p><blockquote><strong>Build with JSON replacement:</strong></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zOIvYdfvYXiZGYGqSAkbFQ.png" /></figure><p><em>Gin uses encoding/json as the default json package but you can change it by building from other tags:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F5SH0sKw1OqC9m_094HDJg.png" /></figure><blockquote><strong>Build without MsgPack rendering feature</strong></blockquote><p><em>Gin enables MsgPack rendering feature by default. But you can disable this feature by specifying nomsgpack build tag:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ITsuEGfE1D6iv66Ub4X3yQ.png" /></figure><p><strong><em>Pros</em></strong></p><ul><li><em>Gin includes only essential features, libraries, and functionalities</em></li><li><em>Extensive documentation available</em></li><li><em>Well-tested and numerous middlewares</em></li><li><em>Reduces boilerplate code</em></li><li><em>Reasonable exception capture and error handling,</em></li><li><em>Fast running speed, good packet routing.</em></li></ul><p><strong><em>Cons</em></strong></p><ul><li><em>Gin is not suitable for applications that require a large backend or several complex server functions and features as it is suited for building REST API.</em></li></ul><p>Some notable<strong> </strong>companies use <strong>Gin Gonic</strong> in their tech stacks, including<em> </em><strong><em>AB180</em></strong><em>, </em><strong><em>SWORD Health</em></strong><em>, </em><strong><em>Teachable,SpartanGeek, Sezzle, and SEASON,Wevox, Aircloset, Screeb, Shippo</em></strong> etc.</p><h3>2. Beego</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*6GkHi3fjbYcWtp0woxvlvg.png" /></figure><p>Beego is the next framework up for review. Beego has great functionalities and features similar to django for python. It is mostly used to develop enterprise web applications. Beego has a fully-fledged Model-View-Controller (MVC) framework with its own libraries and built-in tools.</p><p><strong><em>Example</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wjRqCKISXl9kOrFxt0qY3A.png" /></figure><p><strong><em>Documentation : </em></strong><a href="http://beego.me/docs/intro/"><strong><em>Beego Documentation</em></strong></a></p><p><strong><em>Significant Features:</em></strong></p><ul><li><strong><em>Bee Tool: </em></strong><em>BeeTool watches out for code changes and runs tasks when changes</em></li><li><strong><em>Fully fledged Built in modules: </em></strong><em>Beego has built in ORM system, built-in cache handler, faster processing and traffic routing, session management tools, automated testing and automated deployment.</em></li><li><strong><em>Great Routing and Monitoring: </em></strong><em>It’s also very easy to monitor your QPS, memory and CPU usages, and go routine status.</em></li><li><strong><em>High Performance: </em></strong><em>With native</em> Go http package to handle the requests and the efficient concurrence of go routine, Beego applications can handle massive traffic.</li></ul><p><strong><em>Pros</em></strong></p><ul><li><em>RESTful support,</em></li><li><em>MVC Architecture.</em></li><li><em>Modularity</em></li><li><em>Auto API documents,</em></li><li><em>Annotation router,</em></li><li><em>Faster development,</em></li><li><em>Powerful development tools, Full stack for Web &amp; API.</em></li></ul><p><strong><em>Cons</em></strong></p><ul><li><em>Caching: Beego caches previous versions of pages, which is fine for user experience, but it can lead to silent build failure.</em></li><li><em>Less community support.</em></li></ul><p>Companies using Beego include <strong><em>Getyoutubers, Danale Inc, Huawei Opera, 360, Youdao, Weico, Jd.com, Bmob, Ardan studios, Taobao.com, Tencent games</em></strong><em> etc.</em></p><h3><strong><em>3. Go Kit</em></strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*ezkd5I4_c90Q9TradFyfyw.png" /></figure><p>The <strong>kit </strong>framework is a programming toolkit for building robust, reliable and maintainable microservices in the Golang.kit. This framework gives RPC safety, system observability and infrastructure integration. Kit provides separation of Concerns (transport layer, endpoint layer, service layer). Using go-kit results in clean, reliable and maintainable codebases</p><p><strong><em>REST API:</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C6hS6DMyZasBl8HZDJ7CUg.png" /></figure><p><strong><em>Documentation :</em></strong><a href="https://gokit.io/examples/stringsvc.html"><strong><em> Kit Documentation</em></strong></a></p><p><strong><em>Significant Features</em></strong></p><ul><li><strong><em>Transport: </em></strong><em>Go kit ships with support for HTTP, </em><a href="http://www.grpc.io/"><em>gRPC</em></a><em>, </em><a href="https://thrift.apache.org/"><em>Thrift</em></a><em>, and </em><a href="https://golang.org/pkg/net/rpc/"><em>net/rpc</em></a><em>, NATS, AMQP,Kafka</em></li><li><strong><em>Service Recovery: </em></strong><em>Go kit ships with support for </em><a href="https://consul.io/"><em>Consul</em></a><em>, </em><a href="https://coreos.com/etcd/"><em>etcd</em></a><em>, </em><a href="https://zookeeper.apache.org/"><em>ZooKeeper</em></a><em>, and DNS SRV records.</em></li><li><strong><em>Observability: </em></strong><em>Go kit ships with support for modern monitoring systems like </em><a href="https://prometheus.io/"><em>Prometheus</em></a><em> and </em><a href="https://influxdata.com/"><em>InfluxDB</em></a><em>, as well as more traditional systems like </em><a href="https://github.com/etsy/statsd"><em>statsd</em></a><em>, </em><a href="http://graphite.wikidot.com/"><em>Graphite</em></a><em>, and </em><a href="https://golang.org/pkg/expvar"><em>expvar</em></a><em>, and hosted systems like Datadog via </em><a href="http://docs.datadoghq.com/guides/dogstatsd/"><em>DogStatsD</em></a><em> and </em><a href="http://www.circonus.com/"><em>Circonus</em></a><em>.</em></li><li><strong><em>Logging: </em></strong><em>Go kit’s package log has evolved through many design iterations, extensive benchmarking, and plenty of real-world use to arrive at its current state.</em></li></ul><p><strong><em>Pros</em></strong></p><ul><li><em>Separation of concerns : Go- kit nicely separates the business logic, endpoint and transport,Low-level libraries,</em></li><li><em>The Clean Architecture and Domain-Driven Design</em></li><li><em>Middlewares to encode logic with single responsibility principle,</em></li><li><em>Adapters for common infrastructure components,</em></li><li><em>Makes Go attractive to the organization by providing solutions to common problems of distributed programming like distributed tracing, monitoring and instrumentation, clean architecture.</em></li><li><em>Good for both micro services and monoliths</em></li></ul><p><strong><em>Cons</em></strong></p><ul><li><em>Heavy use of interfaces</em></li><li><em>Overhead of adding API : To create a simple api you need to add a lot of code Function in the interface, Implementation, Endpoint factory function, Transport function, Request encoder, Request decoder, Response encoder and Response decoder, Add the endpoint to the server, Add the endpoint to the client etc.</em></li></ul><h3><strong><em>4 . Echo</em></strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*61ByPxLeN0CnP0xtP9aAvw.png" /></figure><p><a href="https://echo.labstack.com/">Echo</a> is created by Labstack. It is a micro framework consisting of a standard library and a router with very good documentation. Echo allows Developers to define their own middleware and has built-in middleware to use as well.</p><p><strong><em>Example</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MRO_UCxMrk0BF077-5ehGw.png" /></figure><p><strong><em>Documentation :</em></strong><a href="https://echo.labstack.com/guide/"><strong><em> Echo Documentation</em></strong></a></p><p><strong><em>Significant Features</em></strong></p><ul><li><strong><em>Optimized Router:</em></strong><em>Highly optimized HTTP router with zero dynamic memory allocation which smartly prioritizes routes.</em></li><li><strong><em>Scalability: </em></strong><em>Build robust and scalable RESTful API, easily organized into groups.</em></li><li><strong><em>Automatic TLS: </em></strong><em>Automatically install TLS certificates from Let’s Encrypt.</em></li><li><strong><em>HTTP/2 support: </em></strong><em>HTTP/2 support improves speed and provides better user experience.</em></li><li><strong><em>Middlewares: </em></strong><em>Many built-in middleware to use, or define your own. Middleware can beset at root, group or route level.</em></li><li><strong><em>Data Binding : </em></strong><em>Data binding for HTTP request payload, including JSON, XML or form-data.</em></li><li><strong><em>Data Rendering: </em></strong><em>API to send a variety of HTTP responses, including JSON, XML, HTML, File, Attachment, Inline, Stream or Blob.</em></li><li><strong><em>Templating: </em></strong><em>Template rendering using any template engine.</em></li><li><strong><em>Extensibility: </em></strong><em>Customized central HTTP error handling. Easily extendable API.</em></li></ul><p><strong><em>Pros</em></strong></p><ul><li><em>Easy to use</em></li><li><em>Light weight</em></li><li><em>Easily customizable and extensible</em></li><li><em>Minimal</em></li><li><em>High performance</em></li><li><em>Documentation</em></li><li><em>Nicer handler func signature (returning an error)</em></li><li><em>A router without absurd pattern matching issues</em></li><li><em>Centralized HTTP error handling</em></li></ul><p><strong><em>Cons</em></strong></p><ul><li><em>Lack of support</em></li><li><em>Infrequent code updates</em></li></ul><p>some companies reportedly use <strong>Echo</strong> in their tech stacks, including <strong><em>Hepsiburada, tools, GAPO, Modanisa.com, Finema, The Lonero Foundation, FLUX,arivu. one, Nuxi, Agflow, Orangesys, The Lonero Foundation, Ant</em></strong><em> </em><strong><em>Media Server, AI and Robotics</em></strong><a href="https://stackshare.io/ai-and-robotics-ventures/ai-and-robotics-ventures"><strong><em> </em></strong></a><strong><em>ventures </em></strong><em>etc</em><strong><em>.</em></strong></p><h3><strong><em>Other Popular frameworks</em></strong></h3><h3>5. Fiber</h3><p><a href="https://gofiber.io/">Fiber</a> is one of the fastest Go frameworks. Fiber is an express inspired framework with low memory usage and rich routing. Built on top of the Fasthttp which is the fastest HTTP engine for Go, it has been created with the main focus of minimalism.</p><p><strong><em>Example</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cGV9rsAfHO9FrJUqYQDM7g.png" /></figure><p><strong><em>Documentation :</em></strong><a href="https://docs.gofiber.io/"><strong><em> Fiber Documentation</em></strong></a></p><p><strong><em>Significant Features</em></strong></p><ul><li><strong><em>Built-in Rate Limiter:</em></strong><em>Used to limit repeated requests to public APIs and/or endpoints</em></li><li><strong><em>Serve Static Files: </em></strong><em>Static files, like style sheets, scripts, and images can be easily cached, resulting in less memory, and the content remains static upon every request.</em></li><li><strong><em>Extreme performance: </em></strong><em>JSON serialization, database access and server-side template composition.</em></li><li><strong><em>Robust routing</em></strong></li><li><strong><em>Low memory footprint</em></strong></li><li><strong><em>Middleware support</em></strong></li><li><strong><em>Rapid server-side programming</em></strong></li><li><strong><em>Template engines</em></strong></li><li><strong><em>WebSocket support</em></strong></li><li><strong><em>Server-Sent events</em></strong></li><li><strong><em>Translated in 16 languages</em></strong></li></ul><p><strong><em>Pros</em></strong></p><ul><li><em>Rich routing</em></li><li><em>Fast</em></li><li><em>Low memory consumption</em></li><li><em>Support most popular template engines</em></li></ul><p><strong><em>Cons</em></strong></p><ul><li><em>No support for http2</em></li></ul><p>Some of the companies reportedly using Go-Fiber in their tech stacks, including <strong><em>GAPO, Modanisa.com, and Cartesius, issac, bitkub.</em></strong></p><h3><strong><em>6. Revel</em></strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/0*wbZWB0xWnUsrfOue" /></figure><p>A high-productivity fully featured web framework. Revel always ranks as one of the top frameworks on the list and it came up with innovative features and functionalities. It is a self-sufficient framework that does not require any third-party plugins or middleware.</p><p><strong><em>Documentation : </em></strong><a href="https://revel.github.io/tutorial/index.html"><strong><em>Revel Documentation</em></strong></a></p><p><strong><em>Significant Features</em></strong></p><ul><li><strong><em>Full Featured</em></strong><em>: Revel is fully featured out of the box, with packaged libraries and feature sets for everything from small to complex tasks.</em></li><li><strong><em>Hot code reload:</em></strong><em>Code reload tool compiles your code and templates.</em></li><li><strong><em>Comprehensive:</em></strong><em>Revel provides routing, parameter parsing, validation, session/flash, templating, caching, job running, a testing framework and even internationalization.</em></li><li><strong><em>Reusable MVC components</em></strong></li><li><strong><em>Flow control:</em></strong><em>Revel is built around composable middleware called </em><strong><em>filters</em></strong><em>, which implement nearly all request-processing functionality.</em></li><li><strong><em>Stateless:</em></strong><em>Revel provides primitives that keep the web tier stateless for predictable scaling.</em></li><li><strong><em>Go mod ready</em></strong></li></ul><p><strong><em>Pros</em></strong></p><ul><li><em>Fully fledged</em></li><li><em>Efficiency</em></li><li><em>Ease to Learn</em></li><li><em>Popularity</em></li><li><em>Community support</em></li><li><em>No third-party middleware, configuration, plugin and setup]</em></li></ul><p><strong><em>Cons</em></strong></p><ul><li><em>Large codebase: not a lean framework</em></li><li><em>No MongoDB support : mongo support can be added using third party implementations</em></li><li><em>Non idiomatic code</em></li></ul><p>companies reportedly use Revel in their tech stacks, including <strong><em>Atcoder.jp, backend, and Simon G,Jackpot Rising, Adwisely</em></strong></p><h3>7. <strong><em>Gorilla</em></strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/225/0*X1WF6AEN_-3gl2Qy" /></figure><p>Gorilla is one of the top Golang frameworks. Gorilla is popular in the application development communities. Gorilla provides http library’s reusable elements and components. Its’ design is modular, scalable and supports web sockets.</p><p><strong><em>Example</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nJ35AAAaCgkitU6XZT2rNQ.png" /></figure><p><strong><em>Documentation : </em></strong><a href="http://gorillatoolkit.org/pkg/mux"><strong><em>Gorilla Documentation</em></strong></a></p><p><strong><em>Significant Features</em></strong></p><ul><li><em>It implements the http.Handler interface so it is compatible with the standard http.ServeMux.</em></li><li><em>Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.</em></li><li><em>URL hosts, paths and query values can have variables with an optional regular expression.</em></li><li><em>Registered URLs can be built, or “reversed”, which helps maintain references to resources.</em></li><li><em>Routes can be used as sub routers: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.</em></li><li><em>It has Bolster WebSockets</em></li><li><em>Gorilla is also the largest web framework which caters to Net/HTTP library’s reusable components</em></li></ul><p><strong><em>Pros</em></strong></p><ul><li><em>Routing: it’s packed full of features, including support for method-based routing, dynamic URLs, regex route patterns, and host-based routing. Importantly, it’s the only router on this shortlist which </em><strong><em>supports custom routing rules and route ‘reversing’</em></strong><em> . It also allows setting custom handlers for 404 and 405 responses.</em></li><li><em>Gorilla can be easily scaled can add/remove packages, extensions, etc,</em></li><li><em>Reusable elements and components.</em></li></ul><p><strong><em>Cons</em></strong></p><ul><li><em>Configuration effort: Gorilla requires more time and effort to configure components,</em></li><li><em>Performance</em><strong><em>:</em></strong><em> There’s a decrease in performance between Gorilla and other “lean” frameworks.</em></li></ul><h3><strong><em>8. Goji</em></strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/0*Kfl69LBT1NVRw1r4" /></figure><p>Goji is a lightweight, minimalistic and flexible web framework. The features of Goji include re-configurable middleware stack, shutdown, and URL pattern. Goji is a HTTP request multiplexer, similar to net/http.ServeMux .</p><p><strong><em>Example</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7oJCjSKtBlrmGaXy2kYMQA.png" /></figure><p><strong><em>Documentation :</em></strong><a href="https://pkg.go.dev/github.com/zenazn/goji#section-documentation"><strong><em> Goji Documentation</em></strong></a></p><p><strong><em>Significant features</em></strong></p><ul><li><em>Compatible with net/httpURL patterns</em></li><li><em>Reconfigurable middleware stack</em></li><li><em>Context/environment object threaded through middleware and handlers</em></li><li><em>Automatic support for </em><a href="https://github.com/stripe/einhorn"><strong><em>Einhorn</em></strong></a></li><li><em>Graceful shutdown, and zero-downtime graceful reload when combined with Einhorn.</em></li><li><em>supports Web-socket.</em></li></ul><p><strong><em>Pros</em></strong></p><ul><li><em>Thin: an abstraction layer — very minimal ,lightweight and efficient</em></li><li><em>Einhorn: Integrates with Einhorn, a language agnostic socket manager that provides out of the box web socket supportWeb socket assistance to the developers for support</em></li><li><em>Goji has a minimalistic HTTP request multiplexer</em></li><li><em>Stability</em></li><li><em>Not suitable for large enterprise projects.</em></li></ul><h3>Other Mentions:</h3><ul><li><a href="https://gobuffalo.io/">Buffalo</a></li><li><a href="https://github.com/paulbellamy/mango">Mango</a></li><li><a href="https://github.com/go-martini/martini">Martini</a></li><li><a href="https://github.com/gocraft/web">Gocraft</a></li></ul><h3>Final Thoughts</h3><p>Each one of these frameworks have an array of capabilities and functionalities that can be used and adopted. Before you choose the one that is right for your requirements, ensure you fully assess the needs of the project and then recommend the right framework to match those requirements.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=45843d454b63" width="1" height="1" alt=""><hr><p><a href="https://medium.com/propertyfinder-engineering/top-golang-frameworks-for-gophers-45843d454b63">Top Golang Frameworks for Gophers</a> was originally published in <a href="https://medium.com/propertyfinder-engineering">Property Finder Engineering and Tech Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>