Можно потихоньку начинать информировать клиентов о неблагонадежности и нечестной конкуренции со стороны Google и просить их переходить на open source браузеры, Chromium в частности.
В целом современные IT-гиганты больше напоминают колоссов на глиняных ногах, не им то вытанцовывать гопак со своим монопольным положением. Сейчас open-source решений огромное количество. Да, не всегда лучшего качества, да они будут давать больше накладных расходов для бизнеса (хотя в принципе и не всегда это справедливо) но альтернативы есть всегда.
5.3 вышел аж в бородатом 2008 году, но отсутствие пространства имен… в огороде бузина, а в Киеве — дядька.
Единственная проблема PHP так это отсутствие нормальной подержки Unicode и нормальной стандартной билиотеки функций, чье легаси до сих тащится авторами языка из релиза в релиз.
В остальном, отличная реализация ООП, множество фреймворков и библиотек, нормальная производительность.
Я уже упоминал что авторы Go ссылаются на пример возможного использования panic и recovery в пакете json для разворачивания стека вызова функции парсинга и получения общей ошибки. Мой подход ничем не отличается от указанного. habr.com/ru/post/537600/#comment_22554278
Не понимаю почему большинство программистов Go наделяют panic какими-то магическими свойствами. Это стандартная функция библиотеки Go и в документации к ней нигде не написано что она должна использоваться ТОЛЬКО лишь для завершения программы или ТОЛЬКО для обработки специального рода ошибок.
For a real-world example of panic and recover, see the json package from the Go standard library. It encodes an interface with a set of recursive functions. If an error occurs when traversing the value, panic is called to unwind the stack to the top-level function call, which recovers from the panic and returns an appropriate error value (see the 'error' and 'marshal' methods of the encodeState type in encode.go).
Религия тоже предписывает не кушать и не пить во время поста. Я же используя те возможности языка, которые дают сами же авторы особо не злоупотребляя чем либо. Это отлично работает решая поставленные задачи.
В общем я вижу тут очередной goto только в другой ипостасьи.
Панику можно и нужно применять тогда, когда «шеф, усё пропало»
test.Assert и есть тот случай, когда ошибка не позволяет другим задачам продолжать свое выполнение.
«который вы смогли привнести в простой на первый взгляд проект.»
Ну если написание прокси сервера — это простой по Вашему мнению проект, тогда Вам определенно нужно повторить успех Игоря Сысоева ;) Осталось только дописать отдачу статики и реализовать конфигуратор.
1. panic используются в Go для обработок ошибок, не понимаю что значит не Go way, если она родная функции библиотеки Go.
2. В конкретном проекте всего два интерфейса. Я уже говорил об этом в других комментариях к этой статье.
3. Ничего странного на мой взгляд. Простая библиотека для работы с сетевыми соединениями, к тому же еще сырая. Речь не о ней.
4. Нет никакой собственной реализации. В библиотеке используются стандартные механизмы и пакеты «sync» и «runtime».
5. Опять таки, «огромное» — понятие субъективное. В Вашем понимании оно выражается в количественном виде, но если я спрошу какое количество каналов на единицу кода считается уже огромным Вы не сможете мне дать ответ. Посмотрите на кабину современных пассажирских самолетов: огромное количество кнопок, экранов и переключателей. Инженеры тоже по Вашему неправы или так сделано потому что это вытекает из требований и сложности предметной области? В моем случае каналы используются для того для чего их создавали разработчики:
Do not communicate by sharing memory; instead, share memory by communicating.
Можно обсудить то, что Вы не поняли реализацию шаблона. В рожу пользователя там ничего не реализуется. Можно пролистать немного вниз и все увидеть. Я то обязательно поучусь. :)
Ну да, в случае Context тоже не стоит забывать про вызов cancel. И когда на улицу выходишь, тоже нужно не забывать снимать тапочки и надевать ботинки. Поёрничаю немного)
Вы попробуйте написать код для отмены сразу 7 сопроцедур а потом скажите насколько Ваше решение c использованием Context не сложнее моего.
Ещё раз хочу обратить Ваше внимание, что контекст не имеет отношения к многозадачности, это лишь способ переноса информации.
Именно поэтому его используют в: which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Хотя бы потому что интерфейс явно декларирует функциональность пакета. А сам пакет ничего не знает о своем клиенте. Ну а если у него множество клиентов? Каждому клиенту определять интерфейс? Заводить общий? Так его определение уже есть вместе с реализацией.
Я Вас отсылаю опять по ссылке в своем комментарии выше где черному по белому написано:
If a type exists only to implement an interface and will never have exported methods beyond that interface, there is no need to export the type itself. Exporting just the interface makes it clear the value has no interesting behavior beyond what is described in the interface. It also avoids the need to repeat the documentation on every instance of a common method.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Это все реализует Job только на более высоком уровне. Вызов метода Job.Cancel() таким же образом отменит выполнение своих задач. request-scoped values — это тот же Job value, задаваемое через конструктор job.NewJob() или непосредственно через устанавливающий метод .SetValue. К примеру в моей реализацией я переношу через него ссылку на сетевое соединение задачам, которые с ним работают.
Ну а прокидывать сигналы отмены не нужно, это все идет из коробки. Как я же упоминал ранее достаточно вызвать Job.Finish() или Job.Cancel() и все остальное сделает шаблон.
В случае с context.Context их нужно запустить, везде прокинуть context, чтобы иметь возможность их отменять и все это нужно делать руками.
В случае Job, вы просто пишете логику задач не беспокоясь о том как они будут запускаться и как отменяться. В некотором роде тут даже реализуются элементы контрактного программирования. К примеру в примере выше последние 6 методов ожидают установленное соединение в Job value — это клиенты, а задача proxyConn.ProxyConnectTask поставщик этого соединения выполняющая это предусловие. Пока это условие не будет выполнено — эти задачи не запустятся.
В самим задачах критические ошибки вы обрабатываете простыми вызовами task.Assert. Все, больше не о чем беспокоится — Вы сосредотачиваетесь на самой бизнес логике. Как только условия не соблюдено — задачи останавливаются. Job переходит в состояние Cancelled.
If a type exists only to implement an interface and will never have exported methods beyond that interface, there is no need to export the type itself. Exporting just the interface makes it clear the value has no interesting behavior beyond what is described in the interface. It also avoids the need to repeat the documentation on every instance of a common method.
2. Если Вы можете разбить эти «большие» интерфейсы на более мелкие, то сообщите пожалуйста как. Понятие «большой» интерфейс весьма субъективное. Я так понимаю оно у многих измеряется в попугаях.
3. Не совсем понял вопрос.
4. тоже самое
5. Сопроцедур нужно ровно столько сколько нужно. Их создание в Go относительно недорогая операция.
Я уже не стал усложнять до того, чтобы определять какой из backend серверов недоступен. Там есть поддержка ограничения на входящие соединения у прокси сервера и повторное использование соединений к upstream серверу, но не более того.
Более менее просматривал код прокси. Первое, что пришло в голову — вы полностью выбираете body, а потом отдаёте бекенду? Ну… лучше бы так не делать.
Ну почему же, прокси принимает данные и сразу же отправляет их на какой-либо backend сервер:
Вот уже сам backend принимает данные в кадрах с помощью этой библиотеки: github.com/AgentCoop/net-dataframe — то бишь читает пока не получит полный кадр.
Дальше про обработку ошибок — понимаю, что это proof of concept, да и код я смотрел с мобилки, но обработки таймаутов там нет, вариативности ошибок тоже… хотя может и лохо смотрел — вы можете сообщить о недоступности бекэнда или переключиться на живой бекэнд? Если на оба вопроса ответ «нет», то попробуйте добавить этот функционал, и, как мне кажется, тут-то и вылезут нюансы.
Таймауты легко задавать с помощью метода
AddTaskWithIdleTimeout
. Там есть пример в реализации timeout в 2 секунды для клиента:
go func() {
for {
select {
case <- balancerJob.JobDoneNotify():
_, err := balancerJob.GetInterruptedBy()
...
return
}
}
}()
пометив соответствующий сервер как недоступный.
А можно проблему описать словами, а не ссылкой «ту же»? Я не увидел, какое ваш шаблон имеет отношение к контексту, а значит кто-то из нас (либо я либо вы) плохо понимаем, что такое контекст и для чего он. Ну или, как вариант, я просто не понял вашей реализации ;))
Отвечу вопросом на вопрос: а как бы Вы решали задачу, если бы Вам нужно было реализовать прокси сервер? Наверняка же с помощью context.Context :) Потому что Вам нужны были бы сопроцедуры как для чтения/записи данных с клиента, так и для чтения/записи данных c upstream сервера и все это как-то нужно было оркестрировать. Или наверное я тогда действительно не понимаю для чего нужен context.Context, если бы я делал это не с его помощью.
Боюсь если бы я написал статью о DI на Go, то реакция была бы такая же. DI не очень распространен в сообществе Go. FB закончил свои попытки github.com/facebookarchive/inject
В целом современные IT-гиганты больше напоминают колоссов на глиняных ногах, не им то вытанцовывать гопак со своим монопольным положением. Сейчас open-source решений огромное количество. Да, не всегда лучшего качества, да они будут давать больше накладных расходов для бизнеса (хотя в принципе и не всегда это справедливо) но альтернативы есть всегда.
Единственная проблема PHP так это отсутствие нормальной подержки Unicode и нормальной стандартной билиотеки функций, чье легаси до сих тащится авторами языка из релиза в релиз.
В остальном, отличная реализация ООП, множество фреймворков и библиотек, нормальная производительность.
habr.com/ru/post/537600/#comment_22554278
Не понимаю почему большинство программистов Go наделяют panic какими-то магическими свойствами. Это стандартная функция библиотеки Go и в документации к ней нигде не написано что она должна использоваться ТОЛЬКО лишь для завершения программы или ТОЛЬКО для обработки специального рода ошибок.
В статье я упоминал про обмен данными и оркестрирование работы задач посредством ping/pong синхронизации. Это оно и есть.
Как-то ваши слова не совсем вяжутся с применением panic самими же авторами Go
blog.golang.org/defer-panic-and-recover
Это да.
В общем я вижу тут очередной goto только в другой ипостасьи.
test.Assert и есть тот случай, когда ошибка не позволяет другим задачам продолжать свое выполнение.
Ну если написание прокси сервера — это простой по Вашему мнению проект, тогда Вам определенно нужно повторить успех Игоря Сысоева ;) Осталось только дописать отдачу статики и реализовать конфигуратор.
1. panic используются в Go для обработок ошибок, не понимаю что значит не Go way, если она родная функции библиотеки Go.
2. В конкретном проекте всего два интерфейса. Я уже говорил об этом в других комментариях к этой статье.
3. Ничего странного на мой взгляд. Простая библиотека для работы с сетевыми соединениями, к тому же еще сырая. Речь не о ней.
4. Нет никакой собственной реализации. В библиотеке используются стандартные механизмы и пакеты «sync» и «runtime».
5. Опять таки, «огромное» — понятие субъективное. В Вашем понимании оно выражается в количественном виде, но если я спрошу какое количество каналов на единицу кода считается уже огромным Вы не сможете мне дать ответ. Посмотрите на кабину современных пассажирских самолетов: огромное количество кнопок, экранов и переключателей. Инженеры тоже по Вашему неправы или так сделано потому что это вытекает из требований и сложности предметной области? В моем случае каналы используются для того для чего их создавали разработчики:
ps
спасибо, исправлю.
Вы попробуйте написать код для отмены сразу 7 сопроцедур а потом скажите насколько Ваше решение c использованием Context не сложнее моего.
Именно поэтому его используют в: which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Я Вас отсылаю опять по ссылке в своем комментарии выше где черному по белому написано:
и мы бегаем по кругу.
Это все реализует Job только на более высоком уровне. Вызов метода Job.Cancel() таким же образом отменит выполнение своих задач. request-scoped values — это тот же Job value, задаваемое через конструктор job.NewJob() или непосредственно через устанавливающий метод .SetValue. К примеру в моей реализацией я переношу через него ссылку на сетевое соединение задачам, которые с ним работают.
Ну а прокидывать сигналы отмены не нужно, это все идет из коробки. Как я же упоминал ранее достаточно вызвать Job.Finish() или Job.Cancel() и все остальное сделает шаблон.
Вот пример использования WithCancel из официальной документации:
golang.org/pkg/context/#example_WithCancel
Тоже самое но уже с использованием Job:
play.golang.org/p/ge2FUO7a6WU
А теперь представьте как упрощается работа, когда у Вас не одна задача а 5 — 6 или даже 7 как это было в моем случае:
В случае с context.Context их нужно запустить, везде прокинуть context, чтобы иметь возможность их отменять и все это нужно делать руками.
В случае Job, вы просто пишете логику задач не беспокоясь о том как они будут запускаться и как отменяться. В некотором роде тут даже реализуются элементы контрактного программирования. К примеру в примере выше последние 6 методов ожидают установленное соединение в Job value — это клиенты, а задача proxyConn.ProxyConnectTask поставщик этого соединения выполняющая это предусловие. Пока это условие не будет выполнено — эти задачи не запустятся.
В самим задачах критические ошибки вы обрабатываете простыми вызовами task.Assert. Все, больше не о чем беспокоится — Вы сосредотачиваетесь на самой бизнес логике. Как только условия не соблюдено — задачи останавливаются. Job переходит в состояние Cancelled.
2. Если Вы можете разбить эти «большие» интерфейсы на более мелкие, то сообщите пожалуйста как. Понятие «большой» интерфейс весьма субъективное. Я так понимаю оно у многих измеряется в попугаях.
3. Не совсем понял вопрос.
4. тоже самое
5. Сопроцедур нужно ровно столько сколько нужно. Их создание в Go относительно недорогая операция.
Ну почему же, прокси принимает данные и сразу же отправляет их на какой-либо backend сервер:
Вот уже сам backend принимает данные в кадрах с помощью этой библиотеки: github.com/AgentCoop/net-dataframe — то бишь читает пока не получит полный кадр.
Таймауты легко задавать с помощью метода . Там есть пример в реализации timeout в 2 секунды для клиента:
Отловить ошибки соединения тоже не составляет труда. Вот тут она вылезет и прервет выполнение Job.
а обработать ее можно вызовом метода:
пометив соответствующий сервер как недоступный.
Отвечу вопросом на вопрос: а как бы Вы решали задачу, если бы Вам нужно было реализовать прокси сервер? Наверняка же с помощью context.Context :) Потому что Вам нужны были бы сопроцедуры как для чтения/записи данных с клиента, так и для чтения/записи данных c upstream сервера и все это как-то нужно было оркестрировать. Или наверное я тогда действительно не понимаю для чего нужен context.Context, если бы я делал это не с его помощью.