# Fork process with DRb client

**URL:** <https://www.ruby-forum.com/t/fork-process-with-drb-client/64234>\
**Category:** Ruby\
**Created:** [June 23, 2006, 12:02pm UTC](https://www.ruby-forum.com/t/fork-process-with-drb-client/64234 "2006-06-23T12:02:33Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![hanholl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/a87d85/32.png) [@hanholl](https://www.ruby-forum.com/u/hanholl)\
**Post date:** [June 23, 2006, 12:02pm UTC](https://www.ruby-forum.com/t/fork-process-with-drb-client/64234/1 "2006-06-23T12:02:33Z")

</div>

Hello,

If I fork a (Linux) process with a DRb client, both parent and child  
will communicate with the DRb server using the same Unix Domain  
sockets. With predictable, nasty results.

Is there a way for the child to somhow destroy its DRb::DRbObject and  
create a new ?

I’ve scanned the source, but found nothing useful.

Any suggestions ?

Cheers,

Han H.

---

<div class="post-metadata">

**Author:** ![hanholl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/a87d85/32.png) [@hanholl](https://www.ruby-forum.com/u/hanholl)\
**Post date:** [June 23, 2006, 5:57pm UTC](https://www.ruby-forum.com/t/fork-process-with-drb-client/64234/2 "2006-06-23T17:57:55Z")

</div>

On Fri, 23 Jun 2006, Han H. wrote:

> Any suggestions ?
> 
> Cheers,
> 
> Han H.

this seems ok:

harp:~ \> cat a.rb  
require ‘drb’  
require ‘tmpdir’  
require ‘yaml’

STDOUT.sync = STDERR.sync = true

# 

# setup unix domain drb server in another process

# 

```
 r, w = IO.pipe
 uri = nil
 cid = fork

 unless cid
   r.close
   sok = File.join Dir.tmpdir, Process.pid.to_s
   at_exit{ File.unlink sok }
   uri = "drbunix://#{ sok }"
   (list = []).extend DRbUndumped
   DRb.start_service uri, 'children' => list, 'parent' => nil
   w.puts uri
   Thread.new(Thread.current) do |cur|
     begin
       w.puts "no zombies"
     rescue Exception
       cur.exit
     end
   end
   DRb.thread.join
 else
   w.close
   uri = r.gets.strip
 end

```

# 

# attach a client to it

# 

```
 DRb.start_service
 dhash = DRbObject.new nil, uri
 dhash['parent'] = Process.pid

```

# 

# dump info

# 

```
 y 'uri' => uri
 y 'parent' => dhash['parent']
 y 'children' => dhash['children'].map

```

# 

# fork a few children - each one tears down and sets up client again

# 

```
 3.times do
   cid = fork
   unless cid
     DRb.stop_service
     DRb.start_service
     dhash = DRbObject.new nil, uri
     dhash['children'] << Process.pid
     exit
   else
     Process.wait
   end
 end

```

# 

# dump info

# 

```
 y 'uri' => uri
 y 'parent' => dhash['parent']
 y 'children' => dhash['children'].map

```

harp:~ \> ruby a.rb  
uri: drbunix:///tmp/15163  
parent: 15162  
children: []

uri: drbunix:///tmp/15163  
parent: 15162  
children:

- 15165
- 15167
- 15169

regards.

-a

---

<div class="post-metadata">

**Author:** ![hanholl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/a87d85/32.png) [@hanholl](https://www.ruby-forum.com/u/hanholl)\
**Post date:** [June 24, 2006, 5:46pm UTC](https://www.ruby-forum.com/t/fork-process-with-drb-client/64234/3 "2006-06-24T17:46:27Z")

</div>

On Sat, 24 Jun 2006, Han H. wrote:

hi han-

> The problem with this approach is that you have to know the uri of the  
> server at fork time, which can be a problem.

it shouldn’t be, you can do, for example

uri = drbobject.\_\_drburi

eg. if you have a drb object you always have it’s uri. if you have  
it’s uri  
you can always detach and re-attach. though i agree it’s not that  
elegant.

> (And I didn’t realize that you can destroy a DRbObject with  
> DRb.stop\_service – I associate that with the server side of things).

yeah, it seems like it. remember though, every ruby program which uses  
drb is  
a servant - drb is always both server and client. fyi.

> ```
> if f.nil?
> 
> ```
> 
> This just deletes the commection pool in the child. Forking within the  
> mutex is because it’s possible to fork with some other thread having the  
> mutex locked, which causes problems for the one-thread child.

doesn’t it leave open file handles lying around?

> But it’s a bit of a kludge and I would prefer it if DRbObject had a method  
> to deal with it.

agreed. it’s always tough to carry open file handles across a fork -  
sometimes is just seems easier to code around it. for instance, by  
setting up  
a ring server where each service registers in the parent. then all  
children  
simply grab drbobjects of of that ring server. maybe something like  
this  
might apply to your problem:

harp:~ \> ruby a.rb  
[[:key, :val]]  
[:val]

harp:~ \> cat a.rb  
require ‘drb’  
require ‘rinda/ring’  
require ‘rinda/tuplespace’  
require ‘tmpdir’  
require ‘yaml’

STDOUT.sync = STDERR.sync = true  
def start\_ring\_server  
Rinda::RingServer.new Rinda::TupleSpace.new  
end  
def find\_ring\_server  
Rinda::TupleSpaceProxy.new Rinda::RingFinger::new.lookup\_ring\_any  
end  
def drb\_join  
begin; DRb.thread.join; rescue Exception; exit; end  
end  
children = []

# 

# one process starts a ring server. this could also be the parent.

other

# processes, or even the parent, can register drb objects with this

ring

# server.

# 

```
 children <<
   fork{
     DRb.start_service
     rs = start_ring_server
     drb_join
   }

```

# 

# this one starts up a hash server and registers it’s location

# 

```
 children <<
   fork{
     (dhash = {}).extend DRbUndumped
     DRb.start_service nil, dhash
     rs = find_ring_server
     rs.write [:dhash, dhash]
     drb_join
   }

```

# 

# this one starts up an array server and registers it’s location

# 

```
 children <<
   fork{
     (darray = []).extend DRbUndumped
     DRb.start_service nil, darray
     rs = find_ring_server
     rs.write [:darray, darray]
     drb_join
   }

```

# 

# now any child, or the parent, can find and use these drb objects

without

# knowing their locations or requiring a connection before forking -

only

# the ‘name’ of the object need be known.

# 

```
 Process.waitpid fork{
   DRb.start_service
   rs = find_ring_server

   tuple = rs.read [:dhash, nil]
   dhash = tuple.last
   dhash[:key] = :val

   tuple = rs.read [:darray, nil]
   darray = tuple.last
   darray << :val
 }

```

# 

# here the parent finds the dhash and darray to print them out

# 

```
 DRb.start_service
 rs = find_ring_server

 tuple = rs.read [:dhash, nil]
 dhash = tuple.last

 tuple = rs.read [:darray, nil]
 darray = tuple.last

 p dhash.map #=> [[:key, :val]]
 p darray.map #=> [:val]

```

# 

# wait for children

# 

```
 at_exit{
   children.each{|cid| Process.kill 'TERM', cid rescue next}
   loop{ Process.wait Process::WNOHANG rescue break }
 }
 STDIN.gets

```

regards.

-a

---

<div class="post-metadata">

**Author:** ![hanholl](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/a87d85/32.png) [@hanholl](https://www.ruby-forum.com/u/hanholl)\
**Post date:** [June 24, 2006, 4:28pm UTC](https://www.ruby-forum.com/t/fork-process-with-drb-client/64234/4 "2006-06-24T16:28:44Z")

</div>

On 6/23/06, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

[cut]

> ```
> exit
> else
> Process.wait
> 
> ```

[cut]  
Hi Ara,

The problem with this approach is that you have to know the uri of the  
server at fork time, which can be a problem.  
(And I didn’t realize that you can destroy a DRbObject with  
DRb.stop\_service – I associate that with the server side of things).

I’ve found a mote generic way of forking a process that is a DRb  
client, but this has as drawback that it has an initimate knowlegde of  
the way DRb is implemented.  
module DRb  
class DRbConn  
def self.fork  
f = @mutex.synchronize do  
Process::fork  
end  
if f.nil?  
@pool = []  
if block\_given?  
yield  
exit 0  
end  
end  
f  
end  
end  
end

This just deletes the commection pool in the child.  
Forking within the mutex is because it’s possible to fork with some  
other thread having the mutex locked, which causes problems for the  
one-thread child.

But it’s a bit of a kludge and I would prefer it if DRbObject had a  
method to deal with it.

Thanks,

Han H.
