Как стать автором
Обновить
4
0
RouR @RouR

Пользователь

Отправить сообщение

всё целиком нужно сжечь.

Как бы вы обучали своих детей?

Каждое решение имеет свои ограничения, и наше — не исключение.

  • Мы не поддерживаем автоматический решардинг (пока).

  • Мы не поддерживаем multi-shard операции JOIN.

  • Мы не поддерживаем распределенные транзакции.

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

Считаем offset = CalculateHash(shard_key) % BucketNumber. По этому номеру получаем ConnectionString из конфига (не нужно для этого держать отдельную мастер базу и иметь доп.риски отказа), по ConnectionString идём в нужную БД. BucketNumber определяется как константа один раз. А вот количество серверов может быть разным. Перенос отдельной базы на новый сервер это более простая задача, после которой всё что надо будет сделать это поменять соответствующий ConnectionString.

Мы исходим из ситуации, в которой мы приняли решение, что для конкретного проекта сервер ASP.NET должен между запросами не только хранить какие-то статические данные, но и возможно выполнять какую-то полезную работу.

Хранить данные между запросами - как правило для этого используют БД, но можно и кэш.

Статья в основном про кэш. Он может быть: на клиенте, в redis и аналогах, просто in-memory. На тему кэширования написано много статей и лучше. Тема инвалидации кэша вообще не затронута.

"выполнять какую-то полезную работу" в фоне - это background jobs или scheduled jobs.

У вас в статье это всё смешано в кучу и ещё добавлено про DI и юнит тесты.

По большому счёту претензия - "зачем, о чём статья"? Как обучающая - нет, всё поверхностно и "новичково". Как демонстрация лично вашего опыта? Ну не знаю, не хватает чего-то, что нельзя прочитать в учебнике по .Net.

А еще универовцы, как и полагается опытным трейдерам, любили поинвестировать с плечом.

Я слышал другое: там было не плечо, а пирамида РЕПО на облигациях, всё по классике.

У них были клиенты с сегрегированными счетами, и НКЦ продал бумаги с этих счетов.

Возбуждено два уголовных дела в особо крупном размере.

Со временем я конечно привык. Привык и к идее того, что Observable - это новый Promise. <...>
А http запросы? Ну почему, если я хочу принести данные и вызываю функцию getData, я должен делать subscribe?<...>
А потом чешешь затылок и думаешь: и как теперь принести вторую страницу? Ну или просто обновить данные? Снова вызывать getData? Так зачем? Оно же не запускает запрос, а возвращает Observable, и он то у нас уже есть в руках. Вроде уже не получается. Значит нужен subscribe? И тут ещё многие стараются делать unsubscribe запросу в onDestroy. Видимо не понимают, что observable "заканчивается" после запроса.

Я настоятельно рекомендую вам разобраться (почитать или пройти курс) с RxJS и Observable. Там объснят что некоторые observable не "заканчиваются", как кешировать данные стандарным shareReplay и на другие ваши вопросы.

Сейчас пишу проект с RxJS - совсем по другому приходится мыслить и компоновать код, и у этого способа есть свои плюсы. Некоторые вещи становятся очень простыми. Но иногда когнитивная сложность становится большой, впрочем, такое на любом фреймворке можно наговнокодить.

Также отказались от Clickhouse из-за потери данных.

А расскажите чуть подробнее. Для каких целей у вас кликхаус и из-за чего потери.

В продакшене, как правило, запускается несколько инстансов. Предвижу проблемы агрегации счетчиков.

Рискну предположить что у вас в солюшене отдельный проект с веб-контроллерами, отдельный проект с бизнес-логикой, и т.д. Отсюда и проблема куда что положить.

Я так делал когда создавал монолиты. С переходом на небольшие микросервисы это всё кладу в один проект, просто в разных директориях. На хабре была статья про feature-per-folder. Впрочем, есть некоторые исключения для доменых моделей и инфраструктуры, но что касается Requests & Responses - они лежат в том же проекте где и контроллеры и хендлеры.

Что касается контрактов, по swagger спецификации генерируется клиент (C# и/или Typescript) для микросервиса и да, он является отдельным проектом, который импортят все кто хотят работать с этим микросервисом.

//----------------------
// <auto-generated>
//     Generated using the NSwag toolchain v13.13.2.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------

namespace Client.Account.V1_0
{
    using System = global::System;

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.13.2.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v12.0.0.0))")]
    public partial interface IAccountClient_V1_0
    {
      System.Threading.Tasks.Task<RegisterByEmailResponse> RegisterEmailAsync(string api_version = null, RegisterByEmailRequest body = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));    
      ...
    }
    
...    

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v12.0.0.0)")]
    public partial class RegisterByEmailRequest 
    {
        [Newtonsoft.Json.JsonProperty("email", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public string Email { get; set; }
    
        [Newtonsoft.Json.JsonProperty("password", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public string Password { get; set; }
    
       ...
    
    
    }

Подход не нов, что-то похожее видел в servicestack

Прежде всего, MediatR отделяет обработчики запросов от самих запросов.

Я считаю это неудобным.

Но обработчики запросов - отдельные классы. Конечно, мы можем использовать наследование и вынести всё, что нужно, в базовый класс.

Не наследование, надо использовать DI.

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

    [Route("register")]
    [ApiController]
    public class RegisterController
    {        
        [ApiVersion("1.0")]
        [HttpPost("email")]
        public async Task<RegisterByEmail.RegisterByEmailResponse> RegisterByEmail([FromBody] RegisterByEmail.RegisterByEmailRequest request, [FromServices] RegisterByEmail.Handler handler)
        {
            var result = await handler.Handle(request); // это можно улучшить и писать этот бойлерплейт, но считайте что это просто пример
            return result;
        }
		...
        
    }

    public class RegisterByEmail
    {
        public class RegisterByEmailRequest : IRequest<RegisterByEmailResponse>, IValidateable, IHaveUserId, IRequestData
        {
            public string Email { get; set; }
            public string Password { get; set; }
            ...
        }

        public class RegisterByEmailResponse : IErrorable<bool>
        {
            public bool HasError { get; set; }
            public string Message { get; set; }
            public ErrorCode ErrorCode { get; set; }
            public string[] Errors { get; set; }
            public bool Data { get; set; }
        }

        private class Validator : AbstractValidator<RegisterByEmailRequest>
        {
            public Validator()
            {
                RuleFor(field => field.UserId).NotNull().NotEmpty().NotEqual(UserId.Default());
                RuleFor(field => field.Email).NotEmpty().EmailAddress().MaximumLength(Settings.StringMaxLength);
                RuleFor(field => field.Password).NotEmpty().MinimumLength(Settings.PasswordMinLength).MaximumLength(Settings.StringMaxLength);
                ...
            }
        }

        public class Handler : IRequestHandler<RegisterByEmailRequest, RegisterByEmailResponse>
        {
            private readonly IAccountManager _accountManager;
            private readonly ApplicationDbContext _dbContext;
            private readonly ILogger _logger;
            ...

            public Handler(ITracer tracer, ApplicationDbContext dbContext, ...)
            {
                _tracer = tracer;
                _dbContext = dbContext;
                ...
            }

            public async Task<RegisterByEmailResponse> Handle(RegisterByEmailRequest request)
            {
                ...
                return result;
            }
        }
    }
А есть пример, кто попадает под такую формулировку?
Yield хорош для организации конвеера данных. Загрузить с сайта небольшой батч данных в память, отдать через yield, обработать, сохранить, moveNext().
Что такое «рекламное» ПО?
Да, на этом видео они сыграли немного иначе (ну или качество записи повлияло).
Я насчитал 54bpm.
Хочу обратить внимание на очень выраженный шафл-ритм, который основывается на изменении равномерных триолей на две части 1/3 и 2/3. Но в сумме это один такт.
54 *3 = 162 BPM — это если каждую триоль считать одним хитом, что на мой любительский взгляд, неверно.
Дайте послушать блюз в 160 bpm… Texas Flood — Stevie Ray Vaughan

Я насчитал вручную 60bpm.
С учетом комментария выше про 120 bpm, и того что разные люди могут слышать по разному, но как правило быстрее/медленнее строго в 2 раза — в этой композиции точно никак не 160 bpm.

Я пару лет назад пытался для небольшой своей коллекции музыки, автоматом прописать в тэги скорость в bpm. Не работает автоматика. Почти всегда не работает. В итоге определял вручную.
Вы некорректно используете термин обратной связи. Обратная связь, грубо, это когда ученики могут влиять на учителя. Необязательно напрямую, возможно через цепочку родители-администрация. Я понимаю что вы имели ввиду, но термин выбран некорректный.

вызывают ненависть и расстраивают весь настрой класса. Выгнать их нельзя (см. вводное про гарантированное образование)
Их можно перевести в другой класс. Всегда существовали коррекционные классы в которые попасть было непрестижно. Всегда были классы с физ-мат. уклоном, и с уклоном в гуманитарные науки.
но они должны быть инициализированы в теле метода.

Сама статья началась с примера где инициализация отсутствовала. Так что нет, не должны.
Цитируя документацию, вы выделили жирным немного не тот кусок. Обратите внимание на
do not have to be initialized before being passed in a method call

Естественно что буден некорректным ваш вывод про
out-параметры должны быть проинициализированы
Поэтому их надо строить по модели парковок, а не заправок.

Информация

В рейтинге
Не участвует
Откуда
Россия
Зарегистрирован
Активность