0
Posted on Friday, November 09, 2018 by 醉·醉·鱼 and labeled under
You may expect IE will redirect 302 for POST to a GET request. The truth is IE does it. However, the default developer tools sucks.

As you could see from the screenshot below, you will always see POST after 302 response in IE developer tools.

If you see details for these request, you will see both POST and GET requests. How could it be?


While, if you use other network monitor tools to monitor the network, you will see only GET request.


It will bring developers into wrong directions as they would think it's the HTTP method error. For example: https://stackoverflow.com/questions/28513449/ie-ignores-303-redirect-in-post-redirect-get-scenario 

And I would share another IE bug. If there is underscore in your domain, no cookies will be set.

See https://blogs.msdn.microsoft.com/ieinternals/2009/08/20/internet-explorer-cookie-internals-faq/

0
Posted on Tuesday, September 04, 2018 by 醉·醉·鱼 and labeled under

You have a class with a class method. Write a module that, when included, will override that class method.


在这篇文章里面已经介绍了一种方法 http://tech.tulentsev.com/2012/02/ruby-how-to-override-class-method-with-a-module/,但我还可以分享另外的方法。


方法一:用instance_eval。原文中的方法。

module BooModule
  def self.included base
    base.instance_eval do
      def bar
        puts "module"
      end
    end
  end
end

class KlassC

  def self.bar
    puts 'class'
  end
end

KlassC.send(:include, BooModule)

KlassC.bar #=> module
p KlassC.ancestors

方法二:用 class << base ; end


module TooModule
  def self.included base
    class << base
      def bar
        puts "module"
      end
    end
  end
end

class KlassD

  def self.bar
    puts 'class'
  end
end

KlassD.send(:include, TooModule)

KlassD.bar #=> module
p KlassD.ancestors

方法三:用prepend。如果你知道extend实际上就是class << base; include ClassMethods end的话,你就很好理解为啥prepend在这里可以起作用了。前两者都是直接修改类方法,而这直接通过修改继承链的方法去覆盖类方法。


module GooModule
  def self.included base
    class << base
      prepend ClassMethods
    end
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassE
  def self.bar
    puts 'class'
  end
end

KlassE.send(:include, GooModule)

KlassE.bar #=> module
p KlassE.ancestors


能够直接用prepend么?不行。你可以试试下面的例子。虽然说,被prepend的module会放到class的继承链的下方,但实际上,类方法却不受影响。


module FooModule
  def self.included base
    base.extend ClassMethods
  end

  def self.prepended base
    base.extend ClassMethods
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassA
  include FooModule

  def self.bar
    puts 'class'
  end
end


KlassA.bar #=> class
p KlassA.ancestors

class KlassB
  prepend FooModule

  def self.bar
    puts 'class'
  end
end


KlassB.bar #=> class
p KlassB.ancestors
0
Posted on Tuesday, September 04, 2018 by 醉·醉·鱼 and labeled under
最新的5.11.3 minitest不知道为什么,在verbose模式下,把对应的测试 用例的名字给抹掉了。这样的话,导致分析测试用例performance的时候,非常得不友好。

https://github.com/seattlerb/minitest/blob/master/lib/minitest.rb#L617


    def record result # :nodoc:
      io.print "%.2f s = " % [result.time] if options[:verbose]
      io.print result.result_code
      io.puts if options[:verbose]
    end
  end

将上述代码替换成下面代码,就可以看到某个test用掉多少时间。

    def record result # :nodoc:
      io.print "%s#%s = %.2f s = " % [result.klass, result.name, result.time] if options[:verbose]
      io.print result.result_code
      io.puts if options[:verbose]
    end

输出
Run options: -n test_viewing_transaction --verbose --seed 39465

# Running:

TransactionsControllerTest#test_viewing_transaction = 6.13 s = .

Finished in 7.851562s, 0.1274 runs/s, 0.1274 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
0
Posted on Thursday, August 30, 2018 by 醉·醉·鱼 and labeled under

罗列所有container的IP地址

docker ps -q | xargs -n 1 docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} {{ .Name }}'

单独monitor某个contrainer的logs


docker ps -a | grep payments | sed 's/ .*//' | xargs docker logs -f
0
Posted on Tuesday, August 21, 2018 by 醉·醉·鱼 and labeled under , ,
DatabaseCleaner上面的example过时了。按照示例去做的话,会报错 unknown method 'before'。在github上找到了答案,还是比较简单的。


class ActiveSupport::TestCase
  include FactoryGirl::Syntax::Methods

  ActiveRecord::Migration.check_pending!
  DatabaseCleaner.strategy = :truncation
  DatabaseCleaner.logger = Rails.logger
  setup { DatabaseCleaner.start }
  teardown { DatabaseCleaner.clean }
end

配置完成以后,就可以在MYSQL去monitor query,看具体是如何操作数据库的。

mysql> SHOW VARIABLES LIKE "general_log%";

+------------------+----------------------------+
| Variable_name    | Value                      |
+------------------+----------------------------+
| general_log      | OFF                        |
| general_log_file | /var/run/mysqld/mysqld.log |
+------------------+----------------------------+

mysql> SET GLOBAL general_log = 'ON';

观察log

tail -f -n300 /var/run/mysqld/mysqld.log

最后,重置改动。

mysql> SET GLOBAL general_log = 'OFF';

  1. https://stackoverflow.com/questions/568564/how-can-i-view-live-mysql-queries
  2. https://github.com/metaskills/minitest-spec-rails/issues/44#issuecomment-244155657
0
Posted on Monday, January 22, 2018 by 醉·醉·鱼 and labeled under
之前分析过SQL SERVER的死锁,但基本都是基于READ COMMITTED下的死锁。玩得高级点的,就是key lookup lock。最近不幸玩了MySQL,拿原来的理解去尝试分析,结果不对,然后才发现,MySQL的默认隔离级别是REPEATABLE READ。呵呵~

在RR级别下,除了常规的RECORD LOCK,还有一个GAP LOCK。即两条记录之前的间隙。这样的话,就不会允许在范围内插入数据了。http://blog.csdn.net/wanghai__/article/details/7067118 这里有个很好的例子去模拟死锁。

至于分析锁,首先执行
set global innodb_status_output_locks=on;

然后,再执行
SHOW ENGINE INNODB STATUS \G
就可以拿到所有session的锁了。

-- session 1
mysql> start transaction;
mysql> delete from game_summaries where game_id = 2;

-- session 2
mysql> start transaction;
mysql> delete from game_summaries where game_id = 3;

-- session 1
mysql> insert into game_summaries(game_id, score) values (2, 0);
-- waiting

-- session 2
mysql> insert into game_summaries(game_id, score) values(3, 0);
-- deadlock occurs


Deadlock info

------------------------
LATEST DETECTED DEADLOCK
------------------------
2018-02-11 02:19:51 0x7ff5b7b83700
*** (1) TRANSACTION:
TRANSACTION 365986, ACTIVE 59 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 16, OS thread handle 140693325752064, query id 1184 172.18.0.1 root update
insert into game_summaries(game_id, score) values (2, 0)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3445 page no 4 n bits 72 index index_game_summaries_on_game_id of table `TEST`.`game_summaries` trx id 365986 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000009; asc     ;;
 1: len 4; hex 80000002; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 365987, ACTIVE 45 sec inserting
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 17, OS thread handle 140693326018304, query id 1186 172.18.0.1 root update
insert into game_summaries(game_id, score) values(3, 0)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 3445 page no 4 n bits 72 index index_game_summaries_on_game_id of table `TEST`.`game_summaries` trx id 365987 lock_mode X locks gap before rec
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000009; asc     ;;
 1: len 4; hex 80000002; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3445 page no 4 n bits 72 index index_game_summaries_on_game_id of table `TEST`.`game_summaries` trx id 365987 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000009; asc     ;;
 1: len 4; hex 80000002; asc     ;;

*** WE ROLL BACK TRANSACTION (2)


然后就按照下面两篇文章去分析锁就行了。


  1. http://keithlan.github.io/2017/06/21/innodb_locks_algorithms/
  2. http://keithlan.github.io/2017/06/05/innodb_locks_1/
如果你有SQL SERVER的背景知识,简单来说,就是基本的record lock(以及相关的index),加上gap lock。一旦有gap lock,这个范围内是不允许插入数据的。这就增加了死锁发生的几率。这种情况更多是发生在DELETE & INSERT 组合情况下。
在上面的例子里面,两个delete statement所加的gap lock是不会相互冲突的。但是会阻止后续的插入。