Sunday, March 05, 2017

Memory Exception with SQL Server queries

Hi,

I have tried to benchmark the SQl Server vs SQL Service InMemory tables vs. Redis,
and got a weird error while intensively working with InMemory tables:
System.Data.SqlClient.SqlException: There is insufficient system memory in resource pool 'default' to run this query
The data volumes were absolutely reasonable

It appeared that to fix it we need to limit the SQL Server memory!:) Otherwise it tries to use memory over available.

Thursday, February 09, 2017

Delete in JavaScript

Hello here,

After spending couple of hours understanding why my C++  - baked understanding of delete operator does not work in JavaScript I just another time understood that JavaScript is completely special language.

Here is a deep discussion of how it works:

Tags:
JavaScript delete property delete variable

Monday, January 09, 2017

Better client-server communication: replacing AJAX with WebSockets


We have quite complex reporting application, that was done several dozens AJAX requests from client side to generate a single report. Typically it is either JSON of query results from Google BigQuery or HTML generated by a partial form based on such query results.
Each query could take several seconds to fulfill,  and in view of browser limitations for the number of simultaneous connections, the throttling was visually annoying.

I've got a request to parallelize the requests whenever possible. There were choice of server pulling vs. WebSockets pipeline, so latest is definitely more nice and interesting.

Below is the skeleton of the solution in C# and JavaScript.

The server implementation has several interesting moments: except of WebSockets itself, it provides the partial views by rendering them server-side, preserving the context and locale of ASP.NET main thread. Not sure if it is nice approach, but it works so far.

Service implementation:
    public class ReportsApiController : ApiController    {        [System.Web.Http.HttpGet]        public HttpResponseMessage GetQueryResultByWebSocket()        {            HttpContext.Current.AcceptWebSocketRequest(new MyWebSocketHandler(this));            return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);        }
                           ....
    }
    internal class MyWebSocketHandler : WebSocketHandler
    {
        private static WebSocketCollection _connectedClients;
        private ApiController _controller;
        static MyWebSocketHandler()
        {
            _connectedClients = new WebSocketCollection();
        }
        public MyWebSocketHandler(ApiController controller)
        {
            this._controller = controller;
        }
        public override void OnOpen()
        {
            base.OnOpen();
            _connectedClients.Add(this);
        }
        public override void OnClose()
        {
            _connectedClients.Remove(this);
            base.OnClose();
        }
        public override void OnMessage(string message)
        {
            HttpContext ctx = HttpContext.Current;
            var currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture;
            var currentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
            new Task(() =>
            {
                HttpContext.Current = ctx;
                System.Threading.Thread.CurrentThread.CurrentCulture = currentCulture;
                System.Threading.Thread.CurrentThread.CurrentUICulture = currentUICulture;
                var request =
                    JsonConvert.DeserializeObject(message);
                Debug.WriteLine("Received #{0} @{1} t:{2}", request.id, DateTime.Now,
                    Thread.CurrentThread.ManagedThreadId);
                try
                {
                    if (request.url == "/api/ReportsApi/GetQueryResult")
                    {
                        var data = MyQueriesModel.GetQueryResult(request.queryParams);
                        UmiWebSocketResponse result = new UmiWebSocketResponse
                        {
                            data = data,
                            error = null,
                            id = request.id,
                            timeStampSent = request.timeStampSent
                        };
                        Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
                            Thread.CurrentThread.ManagedThreadId);
                        this.Send(JsonConvert.SerializeObject(result));
                    }
                    else if (request.url == "/api/ReportsApi/GetQueryObjResult")
                    {
                        var jss = new JavaScriptSerializer();
                        jss.MaxJsonLength = int.MaxValue;
                        var data = jss.Serialize(UmiQueriesModel.GetQueryObj(request.queryParams));
                        UmiWebSocketResponse result = new UmiWebSocketResponse
                        {
                            data = data,
                            error = null,
                            id = request.id,
                            timeStampSent = request.timeStampSent
                        };
                        Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
                            Thread.CurrentThread.ManagedThreadId);
                        this.Send(JsonConvert.SerializeObject(result));
                    }
                    else if (request.url == "/api/ReportsApi/GetResource")
                    {
                        var jss = new JavaScriptSerializer();
                        jss.MaxJsonLength = int.MaxValue;
                        var prefix = "MyLibrary.Resources.Reports.";
                        try
                        {
                            var fullNames = request.queryParams.QueryName.Split(',');
                            var data = new Dictionary();
                            foreach (var fullName in fullNames)
                            {
                                int idx = fullName.LastIndexOf('.');
                                var typeName = fullName.Substring(0, idx);
                                var fullTypeName = typeName;
                                var resourceName = fullName.Substring(idx + 1);
                                if (!fullTypeName.StartsWith(prefix))
                                    fullTypeName = prefix + fullTypeName;
                                try
                                {
                                    var rm = new ResourceManager(fullTypeName, Assembly.GetExecutingAssembly());
                                    data.Add(typeName + "." + resourceName, rm.GetString(resourceName));
                                }
                                catch (Exception ex)
                                {
                                    Debug.WriteLine("Error performing resource request: {0}",
                                        request.queryParams == null ? "null" : request.queryParams.QueryName);
                                    data.Add(typeName + "." + resourceName, "");
                                }
                            }
                            UmiWebSocketResponse result = new UmiWebSocketResponse
                            {
                                data = jss.Serialize(data),
                                error = null,
                                id = request.id,
                                timeStampSent = request.timeStampSent
                            };
                            Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
                                Thread.CurrentThread.ManagedThreadId);
                            this.Send(jss.Serialize(result));
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine("Error performing resource request: {0}",
                                request.queryParams == null ? "null" : request.queryParams.QueryName);
                            UmiWebSocketResponse result = new UmiWebSocketResponse
                            {
                                data = "",
                                error = "Error performing resource request",
                                id = request.id,
                                timeStampSent = request.timeStampSent
                            };
                            Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
                                Thread.CurrentThread.ManagedThreadId);
                            this.Send(jss.Serialize(result));
                        }
                    }
                    else
                    {
                        var routeToSearch = request.url.Replace("/PartialViews/", "");
                        var methods = Assembly.GetExecutingAssembly().GetTypes()
                          .Where(t => t.IsSubclassOf(typeof(PartialViewsController)))
                          .SelectMany(t => t.GetMethods())
                          .Where(m =>
                          {
                              if (m.Name == routeToSearch)
                                  return true;
                              System.Web.Mvc.RouteAttribute attr =
                                  m.GetCustomAttributes(typeof(System.Web.Mvc.RouteAttribute), false).FirstOrDefault() as System.Web.Mvc.RouteAttribute;
                              if (attr == null)
                                  return false;
                              return attr.Template == routeToSearch;
                          })
                          .ToArray();
                        if (methods.Length > 0)
                        {
                            var controller = Activator.CreateInstance(methods[0].DeclaringType) as PartialViewsController;
                            string baseUrl = HttpContext.Current
                                .Request
                                .Url
                                .GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
                            var routeData = new RouteData();
                            routeData.Values.Add("controller", controller.GetType().Name.Replace("Controller", ""));
                            var controllerContext = new ControllerContext(
                                new HttpContextWrapper(
                                    new HttpContext(
                                        new HttpRequest(null, baseUrl + request.url, null),
                                        new HttpResponse(null))),
                                routeData, controller);
                            controller.ControllerContext = controllerContext;
                            PartialViewResult pvr;
                            if (methods[0].GetParameters().Length == 2)
                            {
                                pvr = methods[0].Invoke(controller, new object[] { request.queryParams, Type.Missing }) as PartialViewResult;
                            }
                            else if (methods[0].GetParameters().Length == 1)
                            {
                                pvr = methods[0].Invoke(controller, new object[] { request.queryParams }) as PartialViewResult;
                            }
                            else
                            {
                                pvr = methods[0].Invoke(controller, new object[0]) as PartialViewResult;
                            }
                            var data = pvr == null ? null : ConvertPartialViewToString(controller.ControllerContext, pvr);
                            UmiWebSocketResponse result = new UmiWebSocketResponse
                            {
                                data = data,
                                error = null,
                                id = request.id,
                                timeStampSent = request.timeStampSent
                            };
                            Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
                                Thread.CurrentThread.ManagedThreadId);
                            this.Send(JsonConvert.SerializeObject(result));
                        }
                    }
                }
                catch (Exception ex)
                {
                    UmiWebSocketResponse errorResult = new UmiWebSocketResponse
                    {
                        error = ex.Message,
                        data = null,
                        id = request.id,
                        timeStampSent = request.timeStampSent
                    };
                    this.Send(JsonConvert.SerializeObject(errorResult));
                }
            }).Start();
        }
        private string ConvertPartialViewToString(ControllerContext controllerContext, PartialViewResult partialView)
        {
            using (var sw = new StringWriter())
            {
                partialView.View = ViewEngines.Engines
                  .FindPartialView(controllerContext, partialView.ViewName).View;
                var vc = new ViewContext(
                  controllerContext, partialView.View, partialView.ViewData, partialView.TempData, sw);
                partialView.View.Render(vc, sw);
                var partialViewString = sw.GetStringBuilder().ToString();
                return partialViewString;
            }
        }
    }



Client code sample:
    my.infrastructure.webSocketHandler.send({ dataType: 'html', url: "/PartialViews/MyPartialView" }, function (result) {        // do something with result    });


JavaScript client library implementation:

my.infrastructure.useWebSocket = true;
my.infrastructure.webSocketHandler = (function () {
    var uri = (location.protocol === "https:" ? "wss://" : "ws://").concat(window.location.hostname).concat("/api/reportsApi/GetQueryResultByWebSocket");
    var requests = {
    };
    var counter = 0;
    var websocket;
    if (my.infrastructure.useWebSocket) {
        websocket = new WebSocket(uri);
        websocket.onopen = function () {
            console.log("Connected to Web Socket");
        };
        websocket.onerror = function (event) {
            console.log("ERROR CONNECTING TO WEB SOCKET");
        };
        websocket.onmessage = function (event) {
            var message = JSON.parse(event.data);
            message.timeStampReceived = new Date();
            var id = message.id;
            if (requests[id]) {
                var request = requests[id];
                console.log(message.timeStampReceived.toISOString() + ": Web Socket response received from " + request.request.url + " (queryName: " + (request.request.queryParams ? request.request.queryParams.queryName : "undefined") + "): "
                    //+ JSON.stringify(message)
                    );
                if (message.Error) {
                    request.onError(message.error);
                } else {
                    var data = message.data;
                    request.onSuccess(data);
                }
                delete requests[request[id]];
            }
        };
    }
    function sendRequest(settings, onSuccess, onError) {
        if (!my.infrastructure.useWebSocket) {
            // do some AJAX if asked for
        }
        var id = counter++;
        var message = {
            id: id,
            queryParams: settings.data,
            url: settings.url,
            type: settings.type,
            dataType: settings.dataType,
            timeStampSent: new Date()
        };
        var messageStr = JSON.stringify(message);
        requests[id] = {
            onSuccess: onSuccess, onError: onError, request: message
        };
        waitForSocketConnection(websocket, function () {
            console.log(message.timeStampSent.toISOString() + ": Web Socket message sent to " + settings.url + " (queryName: " + (message.queryParams ? message.queryParams.queryName : "undefined") + "): "
                //+ messageStr
                );
            websocket.send(messageStr);
        });
    }
    function abortAll() {
        requests = {
        };
    }
    function abortQuery(queryName) {
        $.each(requests, function (index, request) {
            if (request && request.request.queryName === queryName) {
                delete requests[request[id]];
            }
        });
    }
    function waitForSocketConnection(socket, callback) {
        var retryCounter = 3000; // 5 minutes
        setTimeout(
            function () {
                if (socket.readyState === 1) {
                    if (callback != null) {
                        callback();
                    }
                    return;
                } else {
                    if (retryCounter-- > 0) {
                        console.log("Waiting for Web Socket connection...");
                        waitForSocketConnection(socket, callback);
                    }
                }
            }, 100);
    }
    return {
        send: sendRequest,
        abortAll: abortAll,
        abortQuery: abortQuery
    }
})();

Sunday, January 01, 2017

Diving into Angular 2 and NODE.JS world


Hi Everybody,

I will post here my findings in a way of learning Angular 2, VS.CODE and probably MongoDB. So keep updated.

Avoiding the dependencies versioning hell

Once I was stuck with non-compilable NPM-based project because of newly added libraries have brought their incompatible dependencies' version. It was sad and I expected a lot of manual fixes.
But the life is better! Thanks josh3736 from StackOverflow:


Looks like npm-check-updates is the only way to make this happen now.
npm i -g npm-check-updates
npm-check-updates -u
npm install

http://stackoverflow.com/questions/16073603/how-do-i-update-each-dependency-in-package-json-to-the-latest-version

Monday, October 10, 2016

IIS conflicts for port 80 with some applications: 503 Server unavailable or showing Windows Authentication system login dialog

Just spent another half of day solving the same problem already solved before.

If you have these symptoms:
* Http error 503 Server Not Available
or
* System login dialog even as you have no Windows authentication enabled

First of all, look at MS SQL Server Reporting Services configuration.
It creates TWO sites during install at localhost:80/Reports and localhost:80/ReportServer.

You should move both of them to other ports using Reporting Services Configuration Manager utility

The deep root reason is described here:
https://blogs.msdn.microsoft.com/webtopics/2010/02/17/a-not-so-common-root-cause-for-503-service-unavailable/

Another reason possible is Skype messenger. It also likes to take the port 80 preventing others from using it.

Good luck!

PS: Don 't forget about another very simple reason for Error 503:
You might be running your site in IIS under an Application Pool with user account credentials, and your password has just expired!

Monday, October 26, 2015

One more great promotion tool - LinkedIn!

Good morning, and let any fall's rains make you even happier! :)

I got a great idea today - create company profile at LinkedIn.
Looks self-evident, but anyway exciting.

So Ta-Da! https://www.linkedin.com/company/seeyourtravel-com.

Good promotion opportunities and great free visibility!

Friday, October 16, 2015

Wow! CRM!! HubSpot.com!!!

Hi there!

I have just created an account @ HubSpot and it looks cool!!

We have used MS CRM before.. Well so many regrets we've spent time for it..
And most exciting so far - HubSpot even has Kanban board for tasks!!!

Thursday, October 15, 2015

Libraries all around

The second question I would like to stop on in my startup journey are libraries. Not the paper ones this time, but software components we are so dependent on.
So what we wouldn't be where we are without:

  • Leaflet and its plugins for maps: leafletjs.com/ ! Free, stable, and so pleaseant to use!
  • i18next for translations. Nice!
  • jstorage - good wrapper for HTML client storage stuff
  • toastr - simply cool
  • Carousels.... Still a tough question - looking for perfection.
  • JQuery, JQuery UI and its plugins,  and all the standard stuff
Integration libraries or Web API, to be moved to separate article: facebook, google, panoramio,

Startup technology agenda - what addresses mean to you

So, let's start our strartup journey.

First, let's remember all links, sites, urls and integrations we have in some way related to our baby, and maybe some more we would like to be related. Just a shortlist now, with more details to come

Thinking of:
  • Flickr
  • Instagram

Welcome to startup world!

Hello everybody!

Some time ago I have started my small startup - seeyourtravel.com.
I have got many insight and wonderful experience out of it so would like to share them with you in this blog. It is about technology, business, integration, media, PR, hosting, travel industry and many other things around.

Follow, more will come soon!

Wednesday, November 26, 2014


I have found a nice browser-based 3D modelling solution - http://Clara.io. It is amazing what is possible online nowadays :-)

Monday, May 20, 2013

PMP certification - passed!

After all the nervous and preparations the certification is passed. Nice feeling, and good chance for a new challenges, nearer to business now.

Wednesday, November 21, 2012

Treatment of insubordination

Yesterday I met probably the most insolent insubordination ever: one of developers in my project has asked for good recommendation from customer and kindly got it without notifying any superiors.
And (!) tried to use it in contrary to managers' bad opinion about his performance.

Some people would just benefit from being fired a couple of times.

ISTQB Certified - Foundation

Just a citation:
------------------------------------------------------------------------

Congratulations!

Dear Mr. Turevskiy,

You have successfully passed the examination to ISTQB® Certified Tester, Foundation Level.

You scored 35 out of 40 possible credits.
This equals 87,50%.
To pass the exam a minimum of 65% was necessary.

We wish you all the best for your professional future. The certificate will be issued and sent to you within four weeks after the examination fee has been paid. If you have paid by voucher or in advance the certificate will be issued and send to you within four weeks after the examination date.


Kind regards,

Your Certification team

------------------------------------------------------------------------
Yes, I am a PM, not test engineer, but one should know how the activities he manages are done from inside.

Also, learning itself was very usefull to arrange my knowledge of SDLC and fill out the gaps in terms and processes.

Hello PMI

Recently I have started the PMP preparation training and certificatuion preparation.

What I did yet:


So I will put here all the news, links and ideas I have related to the PMI and their activities

PMP certification experience (sorry in russian) http://pmi.org.ua/ru/articles/test

Certification price, procedure and other questions: http://www.pmi.org/en/Certification/~/media/PDF/Certifications/pdc_pmphandbook.ashx

New Agile certification from PMI practice advises: maybe sometimes in future...
 (sorry in russian) http://pmi.org.ua/ru/articles/9067004

Thursday, August 09, 2012

Android NDK setup for Eclipse IDE


Here is a guide that helped
http://mhandroid.wordpress.com/2011/01/23/using-eclipse-for-android-cc-development/

NDK Android Eclipse

Tuesday, March 01, 2011

ASP.NET application does not work: 0x80070021. This configuration section cannot be used at this path

After reinstalling the Windows, Suite ASP.NET application does not work: 0x80070021. This configuration section cannot be used at this path

Unexpectedly help comes from Microsoft Knowledge Base:

http://support.microsoft.com/kb/942055/

See case #9

http://learn.iis.net/page.aspx/145/how-to-use-locking-in-iis-70-configuration

Editing the %windir%\system32\inetsrv\config\applicationHost.config helped.

Error message:

HTTP Error 500.19 - Internal Server Error

The requested page cannot be accessed because the related configuration data for the page is invalid.

Detailed Error Information

Module

AnonymousAuthenticationModule

Notification

AuthenticateRequest

Handler

PageHandlerFactory-ISAPI-2.0-64

Error Code

0x80070021

Config Error

This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".

Config File

\\?\C:\Dev\531Patch00\Root\Web\Logon\web.config