Процессинг в SharePoint

SharePoint обладает всеми свойствами распределенной БД. Разные семейства сайтов могут находиться в разных контентных базах данных. Разные контентные БД могут находиться на разных серверах. Запросы к структурированным данным работают небыстро и самый эффективный способ – обращение по ключу. Часто используется поиск для нахождения нужных данных во всей базе.

Для того чтобы обрабатывать много данных в базах SharePoint  используются задачи таймера, которые выполняют запросы к БД и обрабатывают полученные данные. Но не для всех случаев запросы можно выполнить эффективно.

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

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

Другой подход – создавать процесс с ожиданием до заданного времени. Но процессы тяжеловесны и их использование отражается на интерфейсе пользователя. Кроме того есть ограничения на количество работающих процессов в SharePoint. Тоже плохо масштабируется

Нам нужен способ позволяющий передать данные из фронтэнда (веб-приложения) в бекэнд (службу таймера). В распределенных приложениях для этого используются очереди. Но беглый просмотр API шарепоинта говорит нам что очередей нет, а в SharePoint 2010 нельзя из контекста веб-приложения изменить свойства объектов, унаследованных от SPPersitedObject (подробнее тут), и мы не можем записать что-либо в сам объект задачи таймера или в любой дочерний.

Более детальный просмотр Server OM показал одну маленькую функцию SPSite.AddWorkItem, которая добавляет куда-то workitem, и класс SPWorkItemJobDefinition наследуясь от которого можно определить задачу таймера, разгребающую эти workitem. Вот где прятались очереди в sharepoint.

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

Удивляет отсутствие толковой документации и примеров использования этого метода. Похоже что это внутренний механизм, который частично торчит наружу, но далеко не до всех деталей, которые используют процессы и алерты (да-да, они именно такой метод используют) можно добраться. Тем не менее то что доступно вполне можно использовать для своих целей.



Не используйте Thread.Start

Большинство программистов .NET начинают свое знакомство с асинхронностью и параллельностью с метода Thread.Start. Это полезно для понимания внутренних механизмов работы многопоточности, но очень вредно для написания production кода.

Вызов Thread.Start чаще всего используется в двух случаях: когда вам надо запустить длительные вычисления параллельно с основным потоком и когда необходимо выполнить некоторый вызов без блокировки основного потока. Эти задачи похожи между собой но эффективно реализуются различными способами.

Откладывание вызова

Для данной операции можно использовать

  1. Пул потоков: System.Threading.ThreadPool - не рекомендуется.
  2. SynchronizationContext и его метод Post
  3. TPL

Выполнение длительной операции

Тут немного другие варианты будут удобны:

  1. BackgroundWorker - практически идеальный вариант для GUI так как содержит события для отслеживания хода выполнения.
  2. TPL при использовании продолжений

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

Как можно понять инструменты вроде TPL позволяют работать на нужном уровне абстракции. TPL может использовать SynchronizationContext, ThreadPool или создавать новые потоки для планирования задач.

UPD. Почему же не следует использовать Thread.Start. Это слишком низкоуровневое средство, создание потоков дорогое, нужно писать код для отмены вычислений, писать код для проброса исключений вызывающему методу, нужно, кроме того большое количество потоков в системе снижает производительность.



Linq и обход дерева

Простой код для префиксного обхода дерева.

public static class Treenumerable
{
    public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector)
    {
        return source.SelectMany(e => Traverse(e, childrenSelector));
    }

    public static IEnumerable<T> Traverse<T>(T item, Func<T, IEnumerable<T>> childrenSelector)
    {
        yield return item;
        foreach (var subItem in childrenSelector(item).Traverse(childrenSelector))
        {
            yield return subItem;
        }
    }
}


Чеклист по знания MS SQL 2008

В очередном холиваре на РСДН выкладывал маленький список того что надо знать, чтобы использовать MS SQL эффективно в любой ситуации. Аналогичный чеклист можно сделать для других СУБД. Применять его можно на собеседовании для проверки знаний кандидата.

  1. Операторы SELECT, INSERT, UPDATE, DELETE, MERGE
  2. SELECT INTO, INSERT SELECT, OUTPUT clause
  3. WITH и рекурсивные запросы
  4. JOIN (inner, left, right, full)
  5. Встроенные функции: строковые, математические, ranking functions, преобразования типов итп
  6. Функции: scalar, table, оператор APPLY
  7. Таблицы и колонки: свойства, вычисляемые и хранимые колонки
  8. DML триггеры, before, after, insteadof
  9. View, индексирование View, триггеры на view
  10. Транзакции, ACID, уровни изоляции
  11. Ключи, целостность БД
  12. Нормализация (как минимум до 3 НФ)
  13. Тип данных, хранение, индексирование, использование (в том числе hierarchyid)
  14. Индексы, included columns, статистика
  15. Планы запросов и оптимизация запросов (выбор индекса, подзапросы, функции, агрегаты)
  16. SELECT FOR XML
  17. xml тип данных, запросы к ним, индексирование
  18. BLOBы, хранение и использование, filestream
  19. spatial data
  20. Полнотекстовый поиск, contains\containstable, freetext\freetexttable


Архитектура и дизайн ПО

На тему обсуждения на RSDN.

Целью данного поста является разделение понятия архитектуры и дизайна ПО. Постоянно возникают непонимания чем же эти два понятия отличаются. Одному зачастую приписываются свойства другого.

Итак.

Архитектура ПО — некоторые рамки в пределах которых будет строиться ПО. Например будет ли приложение веб или декстоп, будет ли оно размещено в "облаке" или нет. Будет ли использовать реляционную СУБД или какую-то другую. С какими другими программами придется взаимодействовать и как это делать. Используемые языки и технологии.
Архитектура мало коррелирует с конкретными задачами.
Архитектура определяет подход к решению некоторого класса задач, и наоборот, некоторый класс задач может быть решен определенными архитектурными приемами.


Дизайн ПО — это конкретный набор компонент и связей между ними для решения определенных задач. Для того чтобы заниматься дизайном надо иметь задачи.

Архитектура определяет дизайн. Используемые языки и технологии сильно влияют на используемые паттерны.

Сам процесс дизайна ПО – итеративен по своей природе. Мы придумываем решения задач, создаем прототип, при проверке прототипа возникают новые  задачи или больше узнаем существующих.

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

Еще раз вкратце. дизайн решает задачи, архитектура создает “окружение” для решения задач.