.NET Core MVC, данные продолжают зависать, даже если они установлены как временные - PullRequest
0 голосов
/ 29 апреля 2018

Первоначально я думал, что эта проблема вызвана синглтоном, но у меня есть эта проблема, даже если моя зависимость также установлена ​​как переходная. Все, что делает мой код, - это чтение CSV-файла и сопоставление его с объектом, как показано здесь:

public class CallStatReports
{


    string homeServer = @"\\10.XX.XX.XXX\Reports";
    string csvName = "helpdeskCallStats.csv";
    private int attempts;

    public CallStats TennesseeCallStats { get; set; }
    public CallStats FloridaCallStats { get; set; }

    public CallStats CorporateCallStats { get; set; }
    public CallStats CRCCallStats { get; set; }

    public void RefreshStats()
    {
        var filePath = Path.Combine(homeServer, csvName);

        using (var fileReader = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            using (var reader = new StreamReader(fileReader))
            {
                var cReader = new CsvReader(reader);


                cReader.Configuration.Delimiter = ":";
                cReader.Configuration.ReadingExceptionOccurred = null;
                cReader.Configuration.RegisterClassMap<CallStatsMapper>();

                var results = cReader.GetRecords<CallStats>().ToArray();

                //Sometimes the stream will be empty, so this recursively calls itself until it hits 20 attempts and then returns
                if (results.Count() == 0 && attempts++ <= 20)
                {
                    Thread.Sleep(5);
                    RefreshStats();
                    return;
                }


                TennesseeCallStats = results.FirstOrDefault(x => x.SplitSkill == "Tenn E Emergent");
                FloridaCallStats = results.FirstOrDefault(x => x.SplitSkill == "FL Emergent");
                CorporateCallStats = results.FirstOrDefault(x => x.SplitSkill == "s_68_Corp Users");
                CRCCallStats = results.FirstOrDefault(x => x.SplitSkill == "s_1 Help Desk");

            }
        }
    }

}


public class CallStats
{
    public CallStats()
    {
        SplitSkill = string.Empty;
        SkillState = string.Empty;
        AgentsStaffed = default(int);
        CallsWaiting = default(int);
        OldestCallWaiting = default(TimeSpan);
        ACDCalls = default(int);
        AvgACDTime = default(TimeSpan);
        AbanCalls = default(int);
        AvgAbanTime = default(TimeSpan);
        AvgSpeedAns = default(TimeSpan);

    }

    public string SplitSkill { get; set; }
    public string SkillState { get; set; }
    public int AgentsStaffed { get; set; }
    public int CallsWaiting { get; set; }
    public TimeSpan OldestCallWaiting { get; set; }
    public int ACDCalls { get; set; }
    public TimeSpan AvgACDTime { get; set; }
    public int AbanCalls { get; set; }
    public TimeSpan AvgAbanTime { get; set; }
    public TimeSpan AvgSpeedAns { get; set; }
}


public class AgentReports
{

    string homeServer = @"\\10.XX.XX.XXX\Reports";
    string csvName = "helpdesk.csv";
    private int attempts;

    public List<Agent> CorporateAgents
    {
        get;
        set;
    }
    public List<Agent> CRCAgents
    {
        get;
        set;
    }
    public List<Agent> TennesseeAgents
    {
        get;
        set;
    }

    public List<Agent> FloridaAgents
    {
        get;
        set;
    }


public void RefreshStats()
{
    var filePath = Path.Combine(homeServer, csvName);
    using (var fileReader = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        using (var reader = new StreamReader(fileReader))
        {
            var cReader = new CsvReader(reader);
            cReader.Configuration.Delimiter = ":";
            cReader.Configuration.ReadingExceptionOccurred = null;

            var results = cReader.GetRecords<dynamic>().ToList();

                //Sometimes the stream returns no data, so it recursively calls itself unless the stream was empty 20 times in a row.
                if(results.Count == 0 && attempts++ <= 20)
                {
                    Thread.Sleep(5);
                    RefreshStats();
                    return;
                }
            var convertedAgents = results.Select(x => new Agent()
            {
                AgentName = x.AgentName,
                Icon = int.Parse(x.Icon),
                State = x.State,
                AuxReason = x.AuxReason,
                Skills = new List<string>(((ExpandoObject)x).Where(y => y.Key.ToLower().Contains("skill")).Select(z => z.Value.ToString())),
                LoginID = x.LoginID,
                Time = TimeSpan.FromSeconds(double.Parse(x.Time))
            }).ToList();



            TennesseeAgents = convertedAgents.Where(x => x.Skills.Contains("Tenn E Emergent")).Distinct().ToList();
            FloridaAgents = convertedAgents.Where(x => x.Skills.Contains("FL Emergent")).Distinct().ToList();
            CRCAgents = convertedAgents.Where(x => x.Skills.Contains("s_1 Help Desk")).Distinct().ToList();
            CorporateAgents = convertedAgents.Where(x => x.Skills.Contains("s_68_Corp Users")).Distinct().ToList();

        }
    }

}

Затем у меня есть контроллер, который берет фабричный объект с этими данными и отображает его на веб-странице ....

public class DashboardController : Controller
{
    private DashboardFactory _dashFactory;

    public DashboardController(DashboardFactory dashFactory)
    {
        _dashFactory = dashFactory;
        _dashFactory.AgentReports.RefreshStats();
        _dashFactory.CallStatReports.RefreshStats();
    }

    public IActionResult Index()
    {
        return View(_dashFactory);
    }

    public IActionResult TNAgentView()
    {

        return PartialView("DashView",_dashFactory.TennesseeAgents);
    }

    public IActionResult FLAgentView()
    {
        return PartialView("DashView",_dashFactory.FloridaAgents);
    }

    public IActionResult CorpAgentView()
    {
        return PartialView("DashView",_dashFactory.Corporate);
    }

    public IActionResult CRCAgentView()
    {
        return PartialView("DashView",_dashFactory.CRC);
    }


    public IActionResult CRC()
    {
        return View(_dashFactory.CRC);
    }

    public IActionResult Corporate()
    {
        return View(_dashFactory.Corporate);
    }

    public IActionResult AccessCenter()
    {
        return View(_dashFactory);
    }
}

public  class DashboardFactory
{


    private const int delayTime = 3;

    public DashboardFactory(AgentReports agentReports, CallStatReports callStatReports)
    {
        this.CallStatReports = callStatReports;
        this.AgentReports = agentReports;
        callStatReports.RefreshStats();
        agentReports.RefreshStats();
    }

    public DashModel Corporate
    {
        get
        {
            return new DashModel(AgentReports.CorporateAgents, CallStatReports.CorporateCallStats);
        }
    }

    public DashModel CRC
    {
        get
        {

            return new DashModel(AgentReports.CRCAgents, CallStatReports.CRCCallStats);

        }
    }

    public DashModel FloridaAgents
    {
        get
        {

            return new DashModel(AgentReports.FloridaAgents, CallStatReports.FloridaCallStats);
        }
    }

    public DashModel TennesseeAgents
    {
        get
        {
            return new DashModel(AgentReports.TennesseeAgents, CallStatReports.TennesseeCallStats);
        }
    }

    public CallStatReports CallStatReports { get; }

    public AgentReports AgentReports { get; }
}

Страница самостоятельно обновляется через jquery (представление обновляется каждые 3 секунды с помощью setInterval), но со временем веб-сайт сталкивается с внутренней ошибкой 500 сервера при загрузке данных.

Как только он выдает ошибку , один раз , данные замирают. Объект CallStatReports просто повторяется снова и снова, без обновления. Это почти как если бы использовался один и тот же объект, даже если он помечен как временный при разрешении из контейнера.

Я не могу на всю жизнь понять, почему это происходит. При запуске отладчика он не прерывается в той части, где код возвращает ошибку 500.

1 Ответ

0 голосов
/ 01 мая 2018

Мне удалось выяснить эту проблему, и я надеюсь, что больше никому не придется пройти через ад, который мне пришлось на прошлой неделе, пытаясь решить эту проблему.

Очевидно, если вы читаете данные с общего диска, Windows каким-то образом кэширует данные. Мне удалось воспроизвести эту ошибку, открыв поток 200 раз в секунду.

Через несколько секунд поток откроется с кэшированными данными, даже если файл был обновлен. Это будет сделано только в том случае, если у вас будет файл, который редко изменяется (как в моем случае, количество принятых вызовов будет медленно обновляться)

Поскольку я мог воспроизвести ошибку за несколько секунд, а не за часы ... Я перепробовал много вещей. Ничего не получалось, пока я не решил получить данные на локальном компьютере, вместо того, чтобы пытаться получить их с общего диска удаленно.

То, что немедленно исправило ошибку.

Итак, чтобы кратко объяснить, как я это исправил, я по сути изменил экспорт данных. Вместо того чтобы мой сервер запрашивал данные на общем диске, я настроил свой экспорт таким образом, чтобы вместо этого экспортировать данные напрямую на сервер, который ранее импортировал их через общий ресурс.

Я не гуру Windows, возможно, есть другой способ исправить это, например очистить кэш общего диска ... но это сработало для меня.

...