66use Evenement \EventEmitter ;
77use React \MySQL \Exception ;
88use React \MySQL \Factory ;
9+ use React \EventLoop \LoopInterface ;
10+ use React \MySQL \QueryResult ;
911
1012/**
1113 * @internal
@@ -19,10 +21,22 @@ class LazyConnection extends EventEmitter implements ConnectionInterface
1921 private $ closed = false ;
2022 private $ busy = false ;
2123
22- public function __construct (Factory $ factory , $ uri )
24+ private $ loop ;
25+ private $ idlePeriod = 60.0 ;
26+ private $ idleTimer ;
27+ private $ pending = 0 ;
28+
29+ public function __construct (Factory $ factory , $ uri , LoopInterface $ loop )
2330 {
31+ $ args = array ();
32+ \parse_str (\parse_url ($ uri , \PHP_URL_QUERY ), $ args );
33+ if (isset ($ args ['idle ' ])) {
34+ $ this ->idlePeriod = (float )$ args ['idle ' ];
35+ }
36+
2437 $ this ->factory = $ factory ;
2538 $ this ->uri = $ uri ;
39+ $ this ->loop = $ loop ;
2640 }
2741
2842 private function connecting ()
@@ -36,6 +50,11 @@ private function connecting()
3650 // connection completed => remember only until closed
3751 $ connection ->on ('close ' , function () {
3852 $ this ->connecting = null ;
53+
54+ if ($ this ->idleTimer !== null ) {
55+ $ this ->loop ->cancelTimer ($ this ->idleTimer );
56+ $ this ->idleTimer = null ;
57+ }
3958 });
4059 }, function () {
4160 // connection failed => discard connection attempt
@@ -45,14 +64,49 @@ private function connecting()
4564 return $ connecting ;
4665 }
4766
67+ private function awake ()
68+ {
69+ ++$ this ->pending ;
70+
71+ if ($ this ->idleTimer !== null ) {
72+ $ this ->loop ->cancelTimer ($ this ->idleTimer );
73+ $ this ->idleTimer = null ;
74+ }
75+ }
76+
77+ private function idle ()
78+ {
79+ --$ this ->pending ;
80+
81+ if ($ this ->pending < 1 && $ this ->idlePeriod >= 0 ) {
82+ $ this ->idleTimer = $ this ->loop ->addTimer ($ this ->idlePeriod , function () {
83+ $ this ->connecting ->then (function (ConnectionInterface $ connection ) {
84+ $ connection ->quit ();
85+ });
86+ $ this ->connecting = null ;
87+ $ this ->idleTimer = null ;
88+ });
89+ }
90+ }
91+
4892 public function query ($ sql , array $ params = [])
4993 {
5094 if ($ this ->closed ) {
5195 return \React \Promise \reject (new Exception ('Connection closed ' ));
5296 }
5397
5498 return $ this ->connecting ()->then (function (ConnectionInterface $ connection ) use ($ sql , $ params ) {
55- return $ connection ->query ($ sql , $ params );
99+ $ this ->awake ();
100+ return $ connection ->query ($ sql , $ params )->then (
101+ function (QueryResult $ result ) {
102+ $ this ->idle ();
103+ return $ result ;
104+ },
105+ function (\Exception $ e ) {
106+ $ this ->idle ();
107+ throw $ e ;
108+ }
109+ );
56110 });
57111 }
58112
@@ -64,7 +118,14 @@ public function queryStream($sql, $params = [])
64118
65119 return \React \Promise \Stream \unwrapReadable (
66120 $ this ->connecting ()->then (function (ConnectionInterface $ connection ) use ($ sql , $ params ) {
67- return $ connection ->queryStream ($ sql , $ params );
121+ $ stream = $ connection ->queryStream ($ sql , $ params );
122+
123+ $ this ->awake ();
124+ $ stream ->on ('close ' , function () {
125+ $ this ->idle ();
126+ });
127+
128+ return $ stream ;
68129 })
69130 );
70131 }
@@ -76,7 +137,16 @@ public function ping()
76137 }
77138
78139 return $ this ->connecting ()->then (function (ConnectionInterface $ connection ) {
79- return $ connection ->ping ();
140+ $ this ->awake ();
141+ return $ connection ->ping ()->then (
142+ function () {
143+ $ this ->idle ();
144+ },
145+ function (\Exception $ e ) {
146+ $ this ->idle ();
147+ throw $ e ;
148+ }
149+ );
80150 });
81151 }
82152
@@ -93,6 +163,7 @@ public function quit()
93163 }
94164
95165 return $ this ->connecting ()->then (function (ConnectionInterface $ connection ) {
166+ $ this ->awake ();
96167 return $ connection ->quit ()->then (
97168 function () {
98169 $ this ->close ();
@@ -122,6 +193,11 @@ public function close()
122193 $ this ->connecting = null ;
123194 }
124195
196+ if ($ this ->idleTimer !== null ) {
197+ $ this ->loop ->cancelTimer ($ this ->idleTimer );
198+ $ this ->idleTimer = null ;
199+ }
200+
125201 $ this ->emit ('close ' );
126202 $ this ->removeAllListeners ();
127203 }
0 commit comments